[dali_2.3.21] Merge branch '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 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 Dali::RenderTask SceneView::GetRenderTask()
908 {
909   return mRenderTask;
910 }
911
912 void SceneView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
913 {
914   Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
915
916   if(sceneView)
917   {
918     SceneView& sceneViewImpl(GetImpl(sceneView));
919
920     switch(index)
921     {
922       case Scene3D::SceneView::Property::ALPHA_MASK_URL:
923       {
924         std::string alphaMaskUrl = value.Get<std::string>();
925         sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl);
926         break;
927       }
928       case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
929       {
930         sceneViewImpl.SetMaskContentScaleFactor(value.Get<float>());
931         break;
932       }
933       case Scene3D::SceneView::Property::CROP_TO_MASK:
934       {
935         sceneViewImpl.EnableCropToMask(value.Get<bool>());
936         break;
937       }
938     }
939   }
940 }
941
942 Property::Value SceneView::GetProperty(BaseObject* object, Property::Index index)
943 {
944   Property::Value value;
945
946   Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
947
948   if(sceneView)
949   {
950     SceneView& sceneViewImpl(GetImpl(sceneView));
951
952     switch(index)
953     {
954       case Scene3D::SceneView::Property::ALPHA_MASK_URL:
955       {
956         value = sceneViewImpl.GetAlphaMaskUrl();
957         break;
958       }
959       case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
960       {
961         value = sceneViewImpl.GetMaskContentScaleFactor();
962         break;
963       }
964       case Scene3D::SceneView::Property::CROP_TO_MASK:
965       {
966         value = sceneViewImpl.IsEnabledCropToMask();
967         break;
968       }
969     }
970   }
971   return value;
972 }
973
974 ///////////////////////////////////////////////////////////
975 //
976 // Private methods
977 //
978
979 void SceneView::OnSceneConnection(int depth)
980 {
981   // If diffuse and specular url is not valid, IBL does not need to be loaded.
982   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
983   {
984     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
985   }
986
987   if(!mSkyboxUrl.empty())
988   {
989     UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
990   }
991
992   Window window = DevelWindow::Get(Self());
993   if(window)
994   {
995     // Only for on-screen window
996     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
997
998     mWindow            = window;
999     mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
1000   }
1001
1002   // On-screen / Off-screen window
1003   mSceneHolder = Integration::SceneHolder::Get(Self());
1004   if(mSceneHolder)
1005   {
1006     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1007     mRenderTask             = taskList.CreateTask();
1008     mRenderTask.SetSourceActor(mRootLayer);
1009     mRenderTask.SetExclusive(true);
1010     mRenderTask.SetInputEnabled(true);
1011     mRenderTask.SetCullMode(false);
1012     mRenderTask.SetOrderIndex(SCENE_ORDER_INDEX);
1013     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
1014
1015     UpdateRenderTask();
1016   }
1017
1018   Control::OnSceneConnection(depth);
1019 }
1020
1021 void SceneView::OnSceneDisconnection()
1022 {
1023   mItems.clear();
1024
1025   Window window = mWindow.GetHandle();
1026   if(window)
1027   {
1028     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
1029   }
1030   mWindow.Reset();
1031
1032   if(mSceneHolder)
1033   {
1034     if(mRenderTask)
1035     {
1036       RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1037       taskList.RemoveTask(mRenderTask);
1038       mRenderTask.Reset();
1039     }
1040     if(mShadowMapRenderTask)
1041     {
1042       RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1043       taskList.RemoveTask(mShadowMapRenderTask);
1044       mShadowMapRenderTask.Reset();
1045     }
1046     mSceneHolder.Reset();
1047   }
1048   mFrameBuffer.Reset();
1049   mShadowFrameBuffer.Reset();
1050
1051   Control::OnSceneDisconnection();
1052 }
1053
1054 void SceneView::OnInitialize()
1055 {
1056   Actor self = Self();
1057   mRootLayer = Layer::New();
1058   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
1059   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
1060   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
1061   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
1062   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
1063   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
1064   self.Add(mRootLayer);
1065
1066   mDefaultCamera = Dali::CameraActor::New3DCamera();
1067   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1068   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1069   AddCamera(mDefaultCamera);
1070   UpdateCamera(mDefaultCamera);
1071 }
1072
1073 void SceneView::OnChildAdd(Actor& child)
1074 {
1075   if(child != mRootLayer)
1076   {
1077     mRootLayer.Add(child);
1078   }
1079   Control::OnChildAdd(child);
1080 }
1081
1082 void SceneView::OnChildRemove(Actor& child)
1083 {
1084   mRootLayer.Remove(child);
1085   Control::OnChildRemove(child);
1086 }
1087
1088 float SceneView::GetHeightForWidth(float width)
1089 {
1090   Extents padding;
1091   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1092   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
1093 }
1094
1095 float SceneView::GetWidthForHeight(float height)
1096 {
1097   Extents padding;
1098   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1099   return Control::GetWidthForHeight(height) + padding.start + padding.end;
1100 }
1101
1102 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
1103 {
1104   Control::OnRelayout(size, container);
1105   // Change canvas size of camera actor.
1106   UpdateRenderTask();
1107 }
1108
1109 bool SceneView::IsResourceReady() const
1110 {
1111   return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
1112 }
1113
1114 void SceneView::UpdateCamera(CameraActor camera)
1115 {
1116   if(camera)
1117   {
1118     if(mSelectedCamera && mSelectedCamera.GetParent())
1119     {
1120       mSelectedCamera.Unparent();
1121     }
1122     mRootLayer.Add(camera);
1123   }
1124
1125   mSelectedCamera = camera;
1126   if(mShadowLight)
1127   {
1128     SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
1129   }
1130   UpdateRenderTask();
1131 }
1132
1133 void SceneView::UpdateRenderTask()
1134 {
1135   if(mRenderTask)
1136   {
1137     if(mSelectedCamera != mRenderTask.GetCameraActor())
1138     {
1139       mRenderTask.SetCameraActor(mSelectedCamera);
1140     }
1141     uint32_t width  = GetResolutionWidth();
1142     uint32_t height = GetResolutionHeight();
1143
1144     uint32_t shadowMapBufferSize = std::min(std::max(width, height), MAXIMUM_SIZE_SHADOW_MAP);
1145     UpdateShadowMapBuffer(shadowMapBufferSize);
1146
1147     if(mUseFrameBuffer)
1148     {
1149       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
1150       if(!currentFrameBuffer ||
1151          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), width) ||
1152          !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), height) ||
1153          mMaskingPropertyChanged ||
1154          mWindowSizeChanged)
1155       {
1156         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
1157         mRenderTask.ResetViewportGuideActor();
1158         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
1159
1160         // create offscreen buffer of new size to render our child actors to
1161         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
1162         mFrameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH_STENCIL);
1163         mFrameBuffer.AttachColorTexture(mTexture);
1164         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
1165         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
1166
1167         Property::Map imagePropertyMap;
1168         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
1169         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
1170         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
1171         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
1172         if(!mAlphaMaskUrl.empty())
1173         {
1174           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl);
1175           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, true);
1176           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskContentScaleFactor);
1177           imagePropertyMap.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mCropToMask);
1178           imagePropertyMap.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, Toolkit::DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
1179           Self().RegisterProperty(Y_FLIP_MASK_TEXTURE, FLIP_MASK_TEXTURE);
1180         }
1181
1182         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
1183         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
1184
1185         mRenderTask.SetFrameBuffer(mFrameBuffer);
1186         mRenderTask.SetClearEnabled(true);
1187         mRenderTask.SetClearColor(Color::TRANSPARENT);
1188
1189         mMaskingPropertyChanged = false;
1190         mWindowSizeChanged      = false;
1191       }
1192     }
1193     else
1194     {
1195       mRenderTask.SetViewportGuideActor(Self());
1196       if(mRenderTask.GetFrameBuffer())
1197       {
1198         mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
1199         FrameBuffer framebuffer;
1200         mRenderTask.SetFrameBuffer(framebuffer);
1201         mRenderTask.SetClearEnabled(false);
1202
1203         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
1204
1205         mVisual.Reset();
1206         mFrameBuffer.Reset();
1207         mTexture.Reset();
1208       }
1209     }
1210
1211     if(width > 0u && height > 0u)
1212     {
1213       float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
1214       mSelectedCamera.SetAspectRatio(aspectRatio);
1215     }
1216
1217     RotateCamera();
1218   }
1219 }
1220
1221 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
1222 {
1223   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
1224   RotateCamera();
1225 }
1226
1227 void SceneView::RotateCamera()
1228 {
1229   if(mUseFrameBuffer)
1230   {
1231     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
1232   }
1233   else
1234   {
1235     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
1236   }
1237 }
1238
1239 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
1240 {
1241   bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
1242   if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
1243   {
1244     mSkyboxDirty              = true;
1245     mSkyboxResourceReady      = false;
1246     mSkyboxUrl                = skyboxUrl;
1247     mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
1248   }
1249
1250   if(mSkyboxUrl.empty())
1251   {
1252     if(mSkyboxLoadTask)
1253     {
1254       Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1255       mSkyboxLoadTask.Reset();
1256     }
1257
1258     if(mSkybox)
1259     {
1260       mSkybox.Unparent();
1261       mSkybox.Reset();
1262       mSkyboxTexture.Reset();
1263     }
1264
1265     mSkyboxDirty         = false;
1266     mSkyboxResourceReady = true;
1267
1268     // Request image resource GC
1269     Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1270   }
1271   else
1272   {
1273     if(isOnScene && mSkyboxDirty)
1274     {
1275       if(mSkyboxLoadTask)
1276       {
1277         Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1278         mSkyboxLoadTask.Reset();
1279
1280         // Request image resource GC
1281         Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1282       }
1283
1284       mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
1285       Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
1286       mSkyboxDirty = false;
1287     }
1288   }
1289
1290   if(IsResourceReady())
1291   {
1292     Control::SetResourceReady();
1293   }
1294 }
1295
1296 void SceneView::OnSkyboxLoadComplete()
1297 {
1298   if(!mSkybox)
1299   {
1300     mSkybox = CreateSkybox();
1301     SetSkyboxIntensity(mSkyboxIntensity);
1302     SetSkyboxOrientation(mSkyboxOrientation);
1303     if(mRootLayer)
1304     {
1305       mRootLayer.Add(mSkybox);
1306     }
1307   }
1308
1309   mSkyboxResourceReady = true;
1310   mSkyboxTexture       = mSkyboxLoadTask->GetLoadedTexture();
1311   Shader skyboxShader;
1312   if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
1313   {
1314     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE");
1315   }
1316   else
1317   {
1318     skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_EQUIRECTANGULAR");
1319   }
1320
1321   Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
1322   if(skyboxRenderer)
1323   {
1324     Dali::TextureSet skyboxTextures = TextureSet::New();
1325     skyboxTextures.SetTexture(0, mSkyboxTexture);
1326     skyboxRenderer.SetTextures(skyboxTextures);
1327     skyboxRenderer.SetShader(skyboxShader);
1328   }
1329
1330   mSkyboxLoadTask.Reset();
1331
1332   if(IsResourceReady())
1333   {
1334     Control::SetResourceReady();
1335   }
1336 }
1337
1338 void SceneView::OnIblDiffuseLoadComplete()
1339 {
1340   mDiffuseTexture          = mIblDiffuseLoadTask->GetLoadedTexture();
1341   mIblDiffuseResourceReady = true;
1342   mIblDiffuseLoadTask.Reset();
1343   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1344   {
1345     OnIblLoadComplete();
1346   }
1347 }
1348
1349 void SceneView::OnIblSpecularLoadComplete()
1350 {
1351   mSpecularTexture          = mIblSpecularLoadTask->GetLoadedTexture();
1352   mSpecularMipmapLevels     = mIblSpecularLoadTask->GetMipmapLevels();
1353   mIblSpecularResourceReady = true;
1354   mIblSpecularLoadTask.Reset();
1355   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1356   {
1357     OnIblLoadComplete();
1358   }
1359 }
1360
1361 void SceneView::OnIblLoadComplete()
1362 {
1363   NotifyImageBasedLightTextureChange();
1364   if(IsResourceReady())
1365   {
1366     Control::SetResourceReady();
1367   }
1368 }
1369
1370 void SceneView::NotifyImageBasedLightTextureChange()
1371 {
1372   for(auto&& item : mItems)
1373   {
1374     if(item)
1375     {
1376       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
1377     }
1378   }
1379 }
1380
1381 void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
1382 {
1383   if(!mShadowLight || !mSceneHolder)
1384   {
1385     return;
1386   }
1387
1388   if(!mShadowMapRenderTask)
1389   {
1390     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1391     mShadowMapRenderTask    = taskList.CreateTask();
1392     mShadowMapRenderTask.SetSourceActor(mRootLayer);
1393     mShadowMapRenderTask.SetExclusive(true);
1394     mShadowMapRenderTask.SetInputEnabled(false);
1395     mShadowMapRenderTask.SetCullMode(false);
1396     mShadowMapRenderTask.SetClearEnabled(true);
1397     mShadowMapRenderTask.SetClearColor(Color::WHITE);
1398     mShadowMapRenderTask.SetRenderPassTag(10);
1399     mShadowMapRenderTask.SetCameraActor(GetImplementation(mShadowLight).GetCamera());
1400     mShadowMapRenderTask.SetOrderIndex(SHADOW_ORDER_INDEX);
1401   }
1402
1403   Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
1404   if(!currentShadowFrameBuffer ||
1405      !mShadowTexture ||
1406      !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize))
1407   {
1408     mShadowFrameBuffer.Reset();
1409     mShadowTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize);
1410     mShadowFrameBuffer = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE);
1411     DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
1412     mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
1413
1414     for(auto&& item : mItems)
1415     {
1416       if(item)
1417       {
1418         item->NotifyShadowMapTexture(mShadowTexture);
1419       }
1420     }
1421   }
1422 }
1423
1424 } // namespace Internal
1425 } // namespace Scene3D
1426 } // namespace Dali