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