38e5611f0deb8158b44f6976dbca2d872a9091b0
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / scene-view / scene-view-impl.cpp
1 /*
2  * Copyright (c) 2024 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/common/image-resource-loader.h>
41 #include <dali-scene3d/internal/controls/model/model-impl.h>
42 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
43 #include <dali-scene3d/internal/light/light-impl.h>
44
45 #include <dali/integration-api/debug.h>
46
47 using namespace Dali;
48
49 namespace Dali
50 {
51 namespace Scene3D
52 {
53 namespace Internal
54 {
55 namespace
56 {
57 BaseHandle Create()
58 {
59   return Scene3D::SceneView::New();
60 }
61
62 // Setup properties, signals and actions using the type-registry.
63 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
64
65 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "AlphaMaskUrl", STRING, ALPHA_MASK_URL)
66 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "MaskContentScale", FLOAT, MASK_CONTENT_SCALE)
67 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "CropToMask", BOOLEAN, CROP_TO_MASK)
68 DALI_TYPE_REGISTRATION_END()
69
70 Property::Index    RENDERING_BUFFER        = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
71 constexpr int32_t  DEFAULT_ORIENTATION     = 0;
72 constexpr int32_t  INVALID_INDEX           = -1;
73 constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
74
75 constexpr int32_t SCENE_ORDER_INDEX  = 100;
76 constexpr int32_t SHADOW_ORDER_INDEX = 99;
77
78 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
79 static constexpr std::string_view Y_FLIP_MASK_TEXTURE     = "uYFlipMaskTexture";
80 static constexpr float            FLIP_MASK_TEXTURE       = 1.0f;
81
82 Dali::Actor CreateSkybox()
83 {
84   struct Vertex
85   {
86     Vector3 aPosition;
87   };
88
89   Vertex skyboxVertices[] = {
90     // back
91     {Vector3(-1.0f, 1.0f, -1.0f)},
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
98     // left
99     {Vector3(-1.0f, -1.0f, 1.0f)},
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
106     // right
107     {Vector3(1.0f, -1.0f, -1.0f)},
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
114     // front
115     {Vector3(-1.0f, -1.0f, 1.0f)},
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
122     // botton
123     {Vector3(-1.0f, 1.0f, -1.0f)},
124     {Vector3(1.0f, 1.0f, -1.0f)},
125     {Vector3(1.0f, 1.0f, 1.0f)},
126     {Vector3(1.0f, 1.0f, 1.0f)},
127     {Vector3(-1.0f, 1.0f, 1.0f)},
128     {Vector3(-1.0f, 1.0f, -1.0f)},
129
130     // top
131     {Vector3(-1.0f, -1.0f, -1.0f)},
132     {Vector3(-1.0f, -1.0f, 1.0f)},
133     {Vector3(1.0f, -1.0f, -1.0f)},
134     {Vector3(1.0f, -1.0f, -1.0f)},
135     {Vector3(-1.0f, -1.0f, 1.0f)},
136     {Vector3(1.0f, -1.0f, 1.0f)}};
137
138   Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
139   vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
140
141   Dali::Geometry skyboxGeometry = Geometry::New();
142   skyboxGeometry.AddVertexBuffer(vertexBuffer);
143   skyboxGeometry.SetType(Geometry::TRIANGLES);
144
145   Dali::Shader   shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE");
146   Dali::Renderer skyboxRenderer;
147   skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
148   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
149   // Enables the depth test.
150   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
151   // The fragment shader will run only is those pixels that have the max depth value.
152   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
153
154   Dali::Actor skyboxActor = Actor::New();
155   skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
156   skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
157   skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
158   skyboxActor.AddRenderer(skyboxRenderer);
159   return skyboxActor;
160 }
161
162 void SetShadowLightConstraint(Dali::CameraActor selectedCamera, Dali::CameraActor shadowLightCamera)
163 {
164   shadowLightCamera.SetProperty(Dali::CameraActor::Property::ASPECT_RATIO, 1.0f);
165   shadowLightCamera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 1.0f);
166   shadowLightCamera.SetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE, 0.5f);
167   shadowLightCamera.SetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE, 3.5f);
168
169   //< Make constraint for above properties.
170   shadowLightCamera.RemoveConstraints();
171
172   // Compute ViewProjectionMatrix and store it to "tempViewProjectionMatrix" property
173   auto       tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
174   Constraint projectionMatrixConstraint    = Constraint::New<Matrix>(shadowLightCamera, tempViewProjectionMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs) {
175     Matrix worldMatrix  = inputs[0]->GetMatrix();
176     float  tangentFov_2 = tanf(inputs[4]->GetFloat());
177     float  nearDistance = inputs[5]->GetFloat();
178     float  farDistance  = inputs[6]->GetFloat();
179     float  aspectRatio  = inputs[7]->GetFloat();
180     float  nearY        = 0.0f;
181     float  nearX        = 0.0f;
182     float  farY         = 0.0f;
183     float  farX         = 0.0f;
184     if(inputs[1]->GetInteger() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)
185     {
186       if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
187       {
188         nearY = tangentFov_2 * nearDistance;
189         nearX = nearY * aspectRatio;
190         farY  = tangentFov_2 * farDistance;
191         farX  = farY * aspectRatio;
192       }
193       else
194       {
195         nearX = tangentFov_2 * nearDistance;
196         nearY = nearX / aspectRatio;
197         farX  = tangentFov_2 * farDistance;
198         farY  = farX / aspectRatio;
199       }
200     }
201     else
202     {
203       if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
204       {
205         nearY = inputs[3]->GetFloat();
206         nearX = nearY * aspectRatio;
207       }
208       else
209       {
210         nearX = inputs[3]->GetFloat();
211         nearY = nearX / aspectRatio;
212       }
213       farX = nearX;
214       farY = nearY;
215     }
216
217     std::vector<Vector4> points;
218     points.push_back(Vector4(nearX, nearY, nearDistance, 1.0f));
219     points.push_back(Vector4(-nearX, nearY, nearDistance, 1.0f));
220     points.push_back(Vector4(-nearX, -nearY, nearDistance, 1.0f));
221     points.push_back(Vector4(nearX, -nearY, nearDistance, 1.0f));
222     points.push_back(Vector4(farX, farY, farDistance, 1.0f));
223     points.push_back(Vector4(-farX, farY, farDistance, 1.0f));
224     points.push_back(Vector4(-farX, -farY, farDistance, 1.0f));
225     points.push_back(Vector4(farX, -farY, farDistance, 1.0f));
226
227     Matrix  shadowCameraWorldMatrix = inputs[8]->GetMatrix();
228     Vector4 worldCenter;
229     for(auto&& point : points)
230     {
231       point = worldMatrix * point;
232       worldCenter += point;
233     }
234     worldCenter /= 8.0f;
235     shadowCameraWorldMatrix.SetTranslation(Vector3(worldCenter));
236     Matrix shadowCameraViewMatrix = shadowCameraWorldMatrix;
237     shadowCameraViewMatrix.Invert();
238
239     Vector3 areaMin = Vector3::ONE * MAXFLOAT, areaMax = Vector3::ONE * -MAXFLOAT;
240     for(auto&& point : points)
241     {
242       Vector4 pointV = shadowCameraViewMatrix * point;
243       areaMin.x      = std::min(areaMin.x, pointV.x);
244       areaMin.y      = std::min(areaMin.y, pointV.y);
245       areaMin.z      = std::min(areaMin.z, pointV.z);
246       areaMax.x      = std::max(areaMax.x, pointV.x);
247       areaMax.y      = std::max(areaMax.y, pointV.y);
248       areaMax.z      = std::max(areaMax.z, pointV.z);
249     }
250
251     Vector2 center        = Vector2(areaMax + areaMin) * 0.5;
252     float   delta         = std::max(std::abs(areaMax.x - areaMin.x), std::abs(areaMax.y - areaMin.y));
253     float   delta_2       = delta * 0.5f;
254     Vector2 squareAreaMin = center - Vector2::ONE * delta_2;
255     Vector2 squareAreaMax = center + Vector2::ONE * delta_2;
256     float   deltaZ        = areaMax.z - areaMin.z;
257
258     float right  = -squareAreaMin.x;
259     float left   = -squareAreaMax.x;
260     float top    = squareAreaMin.y;
261     float bottom = squareAreaMax.y;
262     float near   = areaMin.z;
263     float far    = areaMax.z;
264
265     float* projMatrix = output.AsFloat();
266
267     projMatrix[0] = -2.0f / delta;
268     projMatrix[1] = 0.0f;
269     projMatrix[2] = 0.0f;
270     projMatrix[3] = 0.0f;
271
272     projMatrix[4] = 0.0f;
273     projMatrix[5] = -2.0f / delta;
274     projMatrix[6] = 0.0f;
275     projMatrix[7] = 0.0f;
276
277     projMatrix[8]  = 0.0f;
278     projMatrix[9]  = 0.0f;
279     projMatrix[10] = 2.0f / deltaZ;
280     projMatrix[11] = 0.0f;
281
282     projMatrix[12] = -(right + left) / delta;
283     projMatrix[13] = -(top + bottom) / delta;
284     projMatrix[14] = -(near + far) / deltaZ;
285     projMatrix[15] = 1.0f;
286
287     output = output * shadowCameraViewMatrix;
288   });
289   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::Actor::Property::WORLD_MATRIX});
290   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::PROJECTION_MODE});
291   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::PROJECTION_DIRECTION});
292   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE});
293   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FIELD_OF_VIEW});
294   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE});
295   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FAR_PLANE_DISTANCE});
296   projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::ASPECT_RATIO});
297   projectionMatrixConstraint.AddSource(Source{shadowLightCamera, Dali::Actor::Property::WORLD_MATRIX});
298   projectionMatrixConstraint.ApplyPost();
299 }
300
301 } // anonymous namespace
302
303 SceneView::SceneView()
304 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
305   mWindowOrientation(DEFAULT_ORIENTATION),
306   mSkybox(),
307   mSkyboxOrientation(Quaternion()),
308   mSkyboxIntensity(1.0f),
309   mShaderManager(new Scene3D::Loader::ShaderManager())
310 {
311 }
312
313 SceneView::~SceneView()
314 {
315   if(Dali::Adaptor::IsAvailable())
316   {
317     if(mIblDiffuseLoadTask)
318     {
319       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
320       mIblDiffuseLoadTask.Reset();
321     }
322     if(mIblSpecularLoadTask)
323     {
324       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
325       mIblSpecularLoadTask.Reset();
326     }
327     if(mSkyboxLoadTask)
328     {
329       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
330       mSkyboxLoadTask.Reset();
331     }
332
333     // Request image resource GC
334     Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
335   }
336 }
337
338 Dali::Scene3D::SceneView SceneView::New()
339 {
340   SceneView* impl = new SceneView();
341
342   Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
343
344   // Second-phase init of the implementation
345   // This can only be done after the CustomActor connection has been made...
346   impl->Initialize();
347
348   return handle;
349 }
350
351 void SceneView::AddCamera(CameraActor camera)
352 {
353   if(camera)
354   {
355     if(mCameras.empty())
356     {
357       UpdateCamera(camera);
358     }
359     mCameras.push_back(camera);
360   }
361 }
362
363 void SceneView::RemoveCamera(CameraActor camera)
364 {
365   if(camera == mDefaultCamera)
366   {
367     DALI_LOG_ERROR("Default Camera cannot removed.\n");
368     return;
369   }
370
371   if(camera)
372   {
373     for(uint32_t i = 0; i < mCameras.size(); ++i)
374     {
375       if(mCameras[i] == camera)
376       {
377         mCameras.erase(mCameras.begin() + i);
378         break;
379       }
380     }
381
382     if(mSelectedCamera == camera)
383     {
384       CameraActor newCurrentCamera = *mCameras.begin();
385       UpdateCamera(newCurrentCamera);
386     }
387   }
388 }
389
390 uint32_t SceneView::GetCameraCount() const
391 {
392   return mCameras.size();
393 }
394
395 CameraActor SceneView::GetSelectedCamera() const
396 {
397   return mSelectedCamera;
398 }
399
400 CameraActor SceneView::GetCamera(uint32_t index) const
401 {
402   if(index < mCameras.size())
403   {
404     return mCameras[index];
405   }
406   DALI_LOG_ERROR("Input index is out of bounds\n");
407   return CameraActor();
408 }
409
410 CameraActor SceneView::GetCamera(const std::string& name) const
411 {
412   CameraActor returnCamera;
413   for(auto&& camera : mCameras)
414   {
415     if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
416     {
417       returnCamera = camera;
418       break;
419     }
420   }
421   return returnCamera;
422 }
423
424 void SceneView::SelectCamera(uint32_t index)
425 {
426   UpdateCamera(GetCamera(index));
427 }
428
429 void SceneView::SelectCamera(const std::string& name)
430 {
431   UpdateCamera(GetCamera(name));
432 }
433
434 void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item)
435 {
436   if(item)
437   {
438     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
439     item->NotifyShadowMapTexture(mShadowTexture);
440     mItems.push_back(item);
441   }
442 }
443
444 void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item)
445 {
446   if(item)
447   {
448     for(uint32_t i = 0; i < mItems.size(); ++i)
449     {
450       if(mItems[i] == item)
451       {
452         mItems.erase(mItems.begin() + i);
453         break;
454       }
455     }
456   }
457 }
458
459 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
460 {
461   bool needIblReset = false;
462   bool isOnScene    = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
463   if(mDiffuseIblUrl != diffuseUrl)
464   {
465     mDiffuseIblUrl = diffuseUrl;
466     if(mDiffuseIblUrl.empty())
467     {
468       needIblReset = true;
469     }
470     else
471     {
472       mIblDiffuseDirty         = true;
473       mIblDiffuseResourceReady = false;
474     }
475   }
476
477   if(mSpecularIblUrl != specularUrl)
478   {
479     mSpecularIblUrl = specularUrl;
480     if(mSpecularIblUrl.empty())
481     {
482       needIblReset = true;
483     }
484     else
485     {
486       mIblSpecularDirty         = true;
487       mIblSpecularResourceReady = false;
488     }
489   }
490
491   // If one or both of diffuse url and specular url are empty,
492   // we don't need to request to load texture.
493   if(needIblReset)
494   {
495     if(mIblDiffuseLoadTask)
496     {
497       Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
498       mIblDiffuseLoadTask.Reset();
499     }
500
501     if(mIblSpecularLoadTask)
502     {
503       Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
504       mIblSpecularLoadTask.Reset();
505     }
506
507     mIblDiffuseDirty          = false;
508     mIblSpecularDirty         = false;
509     mIblDiffuseResourceReady  = true;
510     mIblSpecularResourceReady = true;
511
512     mDiffuseTexture.Reset();
513     mSpecularTexture.Reset();
514
515     mSpecularMipmapLevels = 1u;
516     NotifyImageBasedLightTextureChange();
517
518     // Request image resource GC
519     Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
520   }
521   else
522   {
523     if(isOnScene && mIblDiffuseDirty)
524     {
525       if(mIblDiffuseLoadTask)
526       {
527         Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
528         mIblDiffuseLoadTask.Reset();
529
530         // Request image resource GC
531         Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
532       }
533       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
534       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
535       mIblDiffuseDirty = false;
536     }
537
538     if(isOnScene && mIblSpecularDirty)
539     {
540       if(mIblSpecularLoadTask)
541       {
542         Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
543         mIblSpecularLoadTask.Reset();
544
545         // Request image resource GC
546         Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
547       }
548       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
549       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
550       mIblSpecularDirty = false;
551     }
552   }
553
554   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
555   {
556     SetImageBasedLightScaleFactor(scaleFactor);
557   }
558
559   // If diffuse and specular textures are already loaded, emits resource ready signal here.
560   if(IsResourceReady())
561   {
562     Control::SetResourceReady();
563   }
564 }
565
566 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
567 {
568   mIblScaleFactor = scaleFactor;
569   for(auto&& item : mItems)
570   {
571     if(item)
572     {
573       item->NotifyImageBasedLightScaleFactor(scaleFactor);
574     }
575   }
576 }
577
578 float SceneView::GetImageBasedLightScaleFactor() const
579 {
580   return mIblScaleFactor;
581 }
582
583 void SceneView::AddLight(Scene3D::Light light)
584 {
585   bool enabled = mShaderManager->AddLight(light);
586   mLights.push_back(std::make_pair(light, enabled));
587
588   if(light.IsShadowEnabled())
589   {
590     SetShadow(light);
591   }
592 }
593
594 void SceneView::RemoveLight(Scene3D::Light light)
595 {
596   mShaderManager->RemoveLight(light);
597   for(uint32_t i = 0; i < mLights.size(); ++i)
598   {
599     if(mLights[i].first == light)
600     {
601       mLights.erase(mLights.begin() + i);
602       break;
603     }
604   }
605
606   if(mLights.size() > mShaderManager->GetLightCount())
607   {
608     for(auto&& waitingLight : mLights)
609     {
610       if(waitingLight.second)
611       {
612         continue;
613       }
614
615       waitingLight.second = mShaderManager->AddLight(waitingLight.first);
616       break;
617     }
618   }
619
620   if(light == mShadowLight)
621   {
622     RemoveShadow(light);
623   }
624
625   if(!mShadowLight)
626   {
627     for(auto&& lightEntity : mLights)
628     {
629       if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
630       {
631         continue;
632       }
633       SetShadow(lightEntity.first);
634       break;
635     }
636   }
637 }
638
639 void SceneView::SetShadow(Scene3D::Light light)
640 {
641   if(!!mShadowLight)
642   {
643     return;
644   }
645
646   auto foundLight = std::find_if(mLights.begin(), mLights.end(), [light](std::pair<Scene3D::Light, bool> lightEntity) -> bool { return (lightEntity.second && lightEntity.first == light); });
647
648   if(foundLight == mLights.end())
649   {
650     return;
651   }
652
653   mShadowLight = light;
654
655   // Directional Light setting.
656   CameraActor lightCamera    = GetImplementation(light).GetCamera();
657   CameraActor selectedCamera = GetSelectedCamera();
658   SetShadowLightConstraint(selectedCamera, lightCamera);
659
660   // make framebuffer for depth map and set it to render task.
661   uint32_t shadowMapBufferSize = std::min(std::max(GetResolutionWidth(), GetResolutionHeight()), MAXIMUM_SIZE_SHADOW_MAP);
662   UpdateShadowMapBuffer(shadowMapBufferSize);
663
664   // use lightCamera as a camera of shadow render task.
665   if(mShadowMapRenderTask)
666   {
667     mShadowMapRenderTask.SetCameraActor(lightCamera);
668   }
669
670   mShaderManager->SetShadow(light);
671   UpdateShadowMapBuffer(shadowMapBufferSize);
672 }
673
674 void SceneView::RemoveShadow(Scene3D::Light light)
675 {
676   if(mShadowLight != light)
677   {
678     return;
679   }
680
681   // remove all constraint from light camera
682   CameraActor lightCamera = GetImplementation(mShadowLight).GetCamera();
683   lightCamera.RemoveConstraints();
684
685   // reset framebuffer and remove it from render task.
686   mShadowFrameBuffer.Reset();
687   mShaderManager->RemoveShadow();
688   if(mShadowMapRenderTask)
689   {
690     mShadowMapRenderTask.SetCameraActor(CameraActor());
691   }
692
693   mShadowLight.Reset();
694
695   mShadowTexture.Reset();
696   for(auto&& item : mItems)
697   {
698     if(item)
699     {
700       item->NotifyShadowMapTexture(mShadowTexture);
701     }
702   }
703
704   for(auto&& lightEntity : mLights)
705   {
706     if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
707     {
708       continue;
709     }
710     SetShadow(lightEntity.first);
711     break;
712   }
713
714   if(mSceneHolder && mShadowMapRenderTask)
715   {
716     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
717     taskList.RemoveTask(mShadowMapRenderTask);
718     mShadowMapRenderTask.Reset();
719   }
720 }
721
722 uint32_t SceneView::GetActivatedLightCount() const
723 {
724   return mShaderManager->GetLightCount();
725 }
726
727 void SceneView::UseFramebuffer(bool useFramebuffer)
728 {
729   if(mUseFrameBuffer != useFramebuffer)
730   {
731     mUseFrameBuffer = useFramebuffer;
732     UpdateRenderTask();
733   }
734 }
735
736 bool SceneView::IsUsingFramebuffer() const
737 {
738   return mUseFrameBuffer;
739 }
740
741 void SceneView::SetResolution(uint32_t width, uint32_t height)
742 {
743   if(mWindowWidth != width || mWindowHeight != height)
744   {
745     mWindowWidth  = width;
746     mWindowHeight = height;
747     if(mUseFrameBuffer)
748     {
749       mWindowSizeChanged = true;
750       UpdateRenderTask();
751     }
752   }
753 }
754
755 uint32_t SceneView::GetResolutionWidth()
756 {
757   if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
758   {
759     return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH));
760   }
761   return mWindowWidth;
762 }
763
764 uint32_t SceneView::GetResolutionHeight()
765 {
766   if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
767   {
768     return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT));
769   }
770   return mWindowHeight;
771 }
772
773 void SceneView::ResetResolution()
774 {
775   SetResolution(0u, 0u);
776 }
777
778 void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
779 {
780   if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
781   {
782     mFrameBufferMultiSamplingLevel = multiSamplingLevel;
783
784     // Create new framebuffer with changed multiSamplingLevel.
785     if(mRenderTask && mFrameBuffer && mTexture)
786     {
787       mFrameBuffer = FrameBuffer::New(GetResolutionWidth(), GetResolutionHeight(), FrameBuffer::Attachment::DEPTH_STENCIL);
788       mFrameBuffer.AttachColorTexture(mTexture);
789       DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
790       mRenderTask.SetFrameBuffer(mFrameBuffer);
791
792       // Note : we don't need to create new visual since visual's url is depend on mTexture.
793     }
794   }
795 }
796
797 uint8_t SceneView::GetFramebufferMultiSamplingLevel() const
798 {
799   return mFrameBufferMultiSamplingLevel;
800 }
801
802 void SceneView::SetSkybox(const std::string& skyboxUrl)
803 {
804   if(mSkyboxUrl != skyboxUrl)
805   {
806     UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
807   }
808 }
809
810 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
811 {
812   if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
813   {
814     UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
815   }
816 }
817
818 void SceneView::SetSkyboxIntensity(float intensity)
819 {
820   mSkyboxIntensity = intensity;
821   if(intensity < 0)
822   {
823     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
824     mSkyboxIntensity = 0.0f;
825   }
826
827   if(mSkybox)
828   {
829     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
830   }
831 }
832
833 float SceneView::GetSkyboxIntensity() const
834 {
835   return mSkyboxIntensity;
836 }
837
838 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
839 {
840   mSkyboxOrientation = orientation;
841   if(mSkybox)
842   {
843     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
844   }
845 }
846
847 Quaternion SceneView::GetSkyboxOrientation() const
848 {
849   return mSkyboxOrientation;
850 }
851
852 Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
853 {
854   return mShaderManager;
855 }
856
857 void SceneView::UpdateShadowUniform(Scene3D::Light light)
858 {
859   mShaderManager->UpdateShadowUniform(light);
860 }
861
862 void SceneView::SetAlphaMaskUrl(std::string& alphaMaskUrl)
863 {
864   if(mAlphaMaskUrl != alphaMaskUrl)
865   {
866     mAlphaMaskUrl           = alphaMaskUrl;
867     mMaskingPropertyChanged = true;
868     UpdateRenderTask();
869   }
870 }
871
872 std::string SceneView::GetAlphaMaskUrl()
873 {
874   return mAlphaMaskUrl;
875 }
876
877 void SceneView::SetMaskContentScaleFactor(float maskContentScaleFactor)
878 {
879   if(mMaskContentScaleFactor != maskContentScaleFactor)
880   {
881     mMaskContentScaleFactor = maskContentScaleFactor;
882     mMaskingPropertyChanged = true;
883     UpdateRenderTask();
884   }
885 }
886
887 float SceneView::GetMaskContentScaleFactor()
888 {
889   return mMaskContentScaleFactor;
890 }
891
892 void SceneView::EnableCropToMask(bool enableCropToMask)
893 {
894   if(mCropToMask != enableCropToMask)
895   {
896     mCropToMask             = enableCropToMask;
897     mMaskingPropertyChanged = true;
898     UpdateRenderTask();
899   }
900 }
901
902 bool SceneView::IsEnabledCropToMask()
903 {
904   return mCropToMask;
905 }
906
907 void SceneView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
908 {
909   Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
910
911   if(sceneView)
912   {
913     SceneView& sceneViewImpl(GetImpl(sceneView));
914
915     switch(index)
916     {
917       case Scene3D::SceneView::Property::ALPHA_MASK_URL:
918       {
919         std::string alphaMaskUrl = value.Get<std::string>();
920         sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl);
921         break;
922       }
923       case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
924       {
925         sceneViewImpl.SetMaskContentScaleFactor(value.Get<float>());
926         break;
927       }
928       case Scene3D::SceneView::Property::CROP_TO_MASK:
929       {
930         sceneViewImpl.EnableCropToMask(value.Get<bool>());
931         break;
932       }
933     }
934   }
935 }
936
937 Property::Value SceneView::GetProperty(BaseObject* object, Property::Index index)
938 {
939   Property::Value value;
940
941   Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
942
943   if(sceneView)
944   {
945     SceneView& sceneViewImpl(GetImpl(sceneView));
946
947     switch(index)
948     {
949       case Scene3D::SceneView::Property::ALPHA_MASK_URL:
950       {
951         value = sceneViewImpl.GetAlphaMaskUrl();
952         break;
953       }
954       case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
955       {
956         value = sceneViewImpl.GetMaskContentScaleFactor();
957         break;
958       }
959       case Scene3D::SceneView::Property::CROP_TO_MASK:
960       {
961         value = sceneViewImpl.IsEnabledCropToMask();
962         break;
963       }
964     }
965   }
966   return value;
967 }
968
969 ///////////////////////////////////////////////////////////
970 //
971 // Private methods
972 //
973
974 void SceneView::OnSceneConnection(int depth)
975 {
976   // If diffuse and specular url is not valid, IBL does not need to be loaded.
977   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
978   {
979     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
980   }
981
982   if(!mSkyboxUrl.empty())
983   {
984     UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
985   }
986
987   Window window = DevelWindow::Get(Self());
988   if(window)
989   {
990     // Only for on-screen window
991     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
992
993     mWindow            = window;
994     mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
995   }
996
997   // On-screen / Off-screen window
998   mSceneHolder = Integration::SceneHolder::Get(Self());
999   if(mSceneHolder)
1000   {
1001     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1002     mRenderTask             = taskList.CreateTask();
1003     mRenderTask.SetSourceActor(mRootLayer);
1004     mRenderTask.SetExclusive(true);
1005     mRenderTask.SetInputEnabled(true);
1006     mRenderTask.SetCullMode(false);
1007     mRenderTask.SetOrderIndex(SCENE_ORDER_INDEX);
1008     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
1009
1010     UpdateRenderTask();
1011   }
1012
1013   Control::OnSceneConnection(depth);
1014 }
1015
1016 void SceneView::OnSceneDisconnection()
1017 {
1018   mItems.clear();
1019
1020   Window window = mWindow.GetHandle();
1021   if(window)
1022   {
1023     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
1024   }
1025   mWindow.Reset();
1026
1027   if(mSceneHolder)
1028   {
1029     if(mRenderTask)
1030     {
1031       RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1032       taskList.RemoveTask(mRenderTask);
1033       mRenderTask.Reset();
1034     }
1035     if(mShadowMapRenderTask)
1036     {
1037       RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1038       taskList.RemoveTask(mShadowMapRenderTask);
1039       mShadowMapRenderTask.Reset();
1040     }
1041     mSceneHolder.Reset();
1042   }
1043   mFrameBuffer.Reset();
1044   mShadowFrameBuffer.Reset();
1045
1046   Control::OnSceneDisconnection();
1047 }
1048
1049 void SceneView::OnInitialize()
1050 {
1051   Actor self = Self();
1052   mRootLayer = Layer::New();
1053   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
1054   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
1055   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
1056   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
1057   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
1058   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
1059   self.Add(mRootLayer);
1060
1061   mDefaultCamera = Dali::CameraActor::New3DCamera();
1062   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1063   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1064   AddCamera(mDefaultCamera);
1065   UpdateCamera(mDefaultCamera);
1066 }
1067
1068 void SceneView::OnChildAdd(Actor& child)
1069 {
1070   if(child != mRootLayer)
1071   {
1072     mRootLayer.Add(child);
1073   }
1074   Control::OnChildAdd(child);
1075 }
1076
1077 void SceneView::OnChildRemove(Actor& child)
1078 {
1079   mRootLayer.Remove(child);
1080   Control::OnChildRemove(child);
1081 }
1082
1083 float SceneView::GetHeightForWidth(float width)
1084 {
1085   Extents padding;
1086   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1087   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
1088 }
1089
1090 float SceneView::GetWidthForHeight(float height)
1091 {
1092   Extents padding;
1093   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1094   return Control::GetWidthForHeight(height) + padding.start + padding.end;
1095 }
1096
1097 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
1098 {
1099   Control::OnRelayout(size, container);
1100   // Change canvas size of camera actor.
1101   UpdateRenderTask();
1102 }
1103
1104 bool SceneView::IsResourceReady() const
1105 {
1106   return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
1107 }
1108
1109 void SceneView::UpdateCamera(CameraActor camera)
1110 {
1111   if(camera)
1112   {
1113     if(mSelectedCamera && mSelectedCamera.GetParent())
1114     {
1115       mSelectedCamera.Unparent();
1116     }
1117     mRootLayer.Add(camera);
1118   }
1119
1120   mSelectedCamera = camera;
1121   if(mShadowLight)
1122   {
1123     SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
1124   }
1125   UpdateRenderTask();
1126 }
1127
1128 void SceneView::UpdateRenderTask()
1129 {
1130   if(mRenderTask)
1131   {
1132     if(mSelectedCamera != mRenderTask.GetCameraActor())
1133     {
1134       mRenderTask.SetCameraActor(mSelectedCamera);
1135     }
1136     uint32_t width  = GetResolutionWidth();
1137     uint32_t height = GetResolutionHeight();
1138
1139     uint32_t shadowMapBufferSize = std::min(std::max(width, height), MAXIMUM_SIZE_SHADOW_MAP);
1140     UpdateShadowMapBuffer(shadowMapBufferSize);
1141
1142     if(mUseFrameBuffer)
1143     {
1144       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
1145       if(!currentFrameBuffer ||
1146          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), width) ||
1147          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), height) ||
1148          mMaskingPropertyChanged ||
1149          mWindowSizeChanged)
1150       {
1151         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
1152         mRenderTask.ResetViewportGuideActor();
1153         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
1154
1155         // create offscreen buffer of new size to render our child actors to
1156         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
1157         mFrameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH_STENCIL);
1158         mFrameBuffer.AttachColorTexture(mTexture);
1159         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
1160         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
1161
1162         Property::Map imagePropertyMap;
1163         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
1164         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
1165         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
1166         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
1167         if(!mAlphaMaskUrl.empty())
1168         {
1169           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl);
1170           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, true);
1171           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskContentScaleFactor);
1172           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mCropToMask);
1173           imagePropertyMap.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, Toolkit::DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
1174           Self().RegisterProperty(Y_FLIP_MASK_TEXTURE, FLIP_MASK_TEXTURE);
1175         }
1176
1177         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
1178         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
1179
1180         mRenderTask.SetFrameBuffer(mFrameBuffer);
1181         mRenderTask.SetClearEnabled(true);
1182         mRenderTask.SetClearColor(Color::TRANSPARENT);
1183
1184         mMaskingPropertyChanged = false;
1185         mWindowSizeChanged      = false;
1186       }
1187     }
1188     else
1189     {
1190       mRenderTask.SetViewportGuideActor(Self());
1191       if(mRenderTask.GetFrameBuffer())
1192       {
1193         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
1194         FrameBuffer framebuffer;
1195         mRenderTask.SetFrameBuffer(framebuffer);
1196         mRenderTask.SetClearEnabled(false);
1197
1198         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
1199
1200         mVisual.Reset();
1201         mFrameBuffer.Reset();
1202         mTexture.Reset();
1203       }
1204     }
1205
1206     if(width > 0u && height > 0u)
1207     {
1208       float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
1209       mSelectedCamera.SetAspectRatio(aspectRatio);
1210     }
1211
1212     RotateCamera();
1213   }
1214 }
1215
1216 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
1217 {
1218   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
1219   RotateCamera();
1220 }
1221
1222 void SceneView::RotateCamera()
1223 {
1224   if(mUseFrameBuffer)
1225   {
1226     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
1227   }
1228   else
1229   {
1230     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
1231   }
1232 }
1233
1234 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
1235 {
1236   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
1237   if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
1238   {
1239     mSkyboxDirty              = true;
1240     mSkyboxResourceReady      = false;
1241     mSkyboxUrl                = skyboxUrl;
1242     mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
1243   }
1244
1245   if(mSkyboxUrl.empty())
1246   {
1247     if(mSkyboxLoadTask)
1248     {
1249       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1250       mSkyboxLoadTask.Reset();
1251     }
1252
1253     if(mSkybox)
1254     {
1255       mSkybox.Unparent();
1256       mSkybox.Reset();
1257       mSkyboxTexture.Reset();
1258     }
1259
1260     mSkyboxDirty         = false;
1261     mSkyboxResourceReady = true;
1262
1263     // Request image resource GC
1264     Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1265   }
1266   else
1267   {
1268     if(isOnScene && mSkyboxDirty)
1269     {
1270       if(mSkyboxLoadTask)
1271       {
1272         Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1273         mSkyboxLoadTask.Reset();
1274
1275         // Request image resource GC
1276         Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1277       }
1278
1279       mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
1280       Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
1281       mSkyboxDirty = false;
1282     }
1283   }
1284
1285   if(IsResourceReady())
1286   {
1287     Control::SetResourceReady();
1288   }
1289 }
1290
1291 void SceneView::OnSkyboxLoadComplete()
1292 {
1293   if(!mSkybox)
1294   {
1295     mSkybox = CreateSkybox();
1296     SetSkyboxIntensity(mSkyboxIntensity);
1297     SetSkyboxOrientation(mSkyboxOrientation);
1298     if(mRootLayer)
1299     {
1300       mRootLayer.Add(mSkybox);
1301     }
1302   }
1303
1304   mSkyboxResourceReady = true;
1305   mSkyboxTexture       = mSkyboxLoadTask->GetLoadedTexture();
1306   Shader skyboxShader;
1307   if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
1308   {
1309     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE");
1310   }
1311   else
1312   {
1313     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_EQUIRECTANGULAR");
1314   }
1315
1316   Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
1317   if(skyboxRenderer)
1318   {
1319     Dali::TextureSet skyboxTextures = TextureSet::New();
1320     skyboxTextures.SetTexture(0, mSkyboxTexture);
1321     skyboxRenderer.SetTextures(skyboxTextures);
1322     skyboxRenderer.SetShader(skyboxShader);
1323   }
1324
1325   mSkyboxLoadTask.Reset();
1326
1327   if(IsResourceReady())
1328   {
1329     Control::SetResourceReady();
1330   }
1331 }
1332
1333 void SceneView::OnIblDiffuseLoadComplete()
1334 {
1335   mDiffuseTexture          = mIblDiffuseLoadTask->GetLoadedTexture();
1336   mIblDiffuseResourceReady = true;
1337   mIblDiffuseLoadTask.Reset();
1338   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1339   {
1340     OnIblLoadComplete();
1341   }
1342 }
1343
1344 void SceneView::OnIblSpecularLoadComplete()
1345 {
1346   mSpecularTexture          = mIblSpecularLoadTask->GetLoadedTexture();
1347   mSpecularMipmapLevels     = mIblSpecularLoadTask->GetMipmapLevels();
1348   mIblSpecularResourceReady = true;
1349   mIblSpecularLoadTask.Reset();
1350   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1351   {
1352     OnIblLoadComplete();
1353   }
1354 }
1355
1356 void SceneView::OnIblLoadComplete()
1357 {
1358   NotifyImageBasedLightTextureChange();
1359   if(IsResourceReady())
1360   {
1361     Control::SetResourceReady();
1362   }
1363 }
1364
1365 void SceneView::NotifyImageBasedLightTextureChange()
1366 {
1367   for(auto&& item : mItems)
1368   {
1369     if(item)
1370     {
1371       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
1372     }
1373   }
1374 }
1375
1376 void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
1377 {
1378   if(!mShadowLight || !mSceneHolder)
1379   {
1380     return;
1381   }
1382
1383   if(!mShadowMapRenderTask)
1384   {
1385     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1386     mShadowMapRenderTask    = taskList.CreateTask();
1387     mShadowMapRenderTask.SetSourceActor(mRootLayer);
1388     mShadowMapRenderTask.SetExclusive(true);
1389     mShadowMapRenderTask.SetInputEnabled(false);
1390     mShadowMapRenderTask.SetCullMode(false);
1391     mShadowMapRenderTask.SetClearEnabled(true);
1392     mShadowMapRenderTask.SetClearColor(Color::WHITE);
1393     mShadowMapRenderTask.SetRenderPassTag(10);
1394     mShadowMapRenderTask.SetCameraActor(GetImplementation(mShadowLight).GetCamera());
1395     mShadowMapRenderTask.SetOrderIndex(SHADOW_ORDER_INDEX);
1396   }
1397
1398   Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
1399   if(!currentShadowFrameBuffer ||
1400      !mShadowTexture ||
1401      !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize))
1402   {
1403     mShadowFrameBuffer.Reset();
1404     mShadowTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize);
1405     mShadowFrameBuffer = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE);
1406     DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
1407     mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
1408
1409     for(auto&& item : mItems)
1410     {
1411       if(item)
1412       {
1413         item->NotifyShadowMapTexture(mShadowTexture);
1414       }
1415     }
1416   }
1417 }
1418
1419 } // namespace Internal
1420 } // namespace Scene3D
1421 } // namespace Dali