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