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