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