Add Skybox in SceneView
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / scene-view / scene-view-impl.cpp
1 /*
2  * Copyright (c) 2022 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/integration-api/debug.h>
32 #include <dali/public-api/object/type-registry-helper.h>
33 #include <dali/public-api/object/type-registry.h>
34 #include <string_view>
35
36 // INTERNAL INCLUDES
37 #include <dali-scene3d/internal/controls/model/model-impl.h>
38 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
39 #include <dali-scene3d/public-api/loader/cube-map-loader.h>
40
41 #include <dali/integration-api/debug.h>
42
43 using namespace Dali;
44
45 namespace Dali
46 {
47 namespace Scene3D
48 {
49 namespace Internal
50 {
51 namespace
52 {
53 BaseHandle Create()
54 {
55   return Scene3D::SceneView::New();
56 }
57
58 // Setup properties, signals and actions using the type-registry.
59 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
60 DALI_TYPE_REGISTRATION_END()
61
62 Property::Index   RENDERING_BUFFER    = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
63 constexpr int32_t DEFAULT_ORIENTATION = 0;
64
65 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
66
67 Dali::Actor CreateSkybox(const std::string& skyboxUrl)
68 {
69   struct Vertex
70   {
71     Vector3 aPosition;
72   };
73
74   Vertex skyboxVertices[] = {
75     // back
76     {Vector3(-1.0f, 1.0f, -1.0f)},
77     {Vector3(-1.0f, -1.0f, -1.0f)},
78     {Vector3(1.0f, -1.0f, -1.0f)},
79     {Vector3(1.0f, -1.0f, -1.0f)},
80     {Vector3(1.0f, 1.0f, -1.0f)},
81     {Vector3(-1.0f, 1.0f, -1.0f)},
82
83     // left
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     {Vector3(-1.0f, 1.0f, -1.0f)},
88     {Vector3(-1.0f, 1.0f, 1.0f)},
89     {Vector3(-1.0f, -1.0f, 1.0f)},
90
91     // right
92     {Vector3(1.0f, -1.0f, -1.0f)},
93     {Vector3(1.0f, -1.0f, 1.0f)},
94     {Vector3(1.0f, 1.0f, 1.0f)},
95     {Vector3(1.0f, 1.0f, 1.0f)},
96     {Vector3(1.0f, 1.0f, -1.0f)},
97     {Vector3(1.0f, -1.0f, -1.0f)},
98
99     // front
100     {Vector3(-1.0f, -1.0f, 1.0f)},
101     {Vector3(-1.0f, 1.0f, 1.0f)},
102     {Vector3(1.0f, 1.0f, 1.0f)},
103     {Vector3(1.0f, 1.0f, 1.0f)},
104     {Vector3(1.0f, -1.0f, 1.0f)},
105     {Vector3(-1.0f, -1.0f, 1.0f)},
106
107     // botton
108     {Vector3(-1.0f, 1.0f, -1.0f)},
109     {Vector3(1.0f, 1.0f, -1.0f)},
110     {Vector3(1.0f, 1.0f, 1.0f)},
111     {Vector3(1.0f, 1.0f, 1.0f)},
112     {Vector3(-1.0f, 1.0f, 1.0f)},
113     {Vector3(-1.0f, 1.0f, -1.0f)},
114
115     // top
116     {Vector3(-1.0f, -1.0f, -1.0f)},
117     {Vector3(-1.0f, -1.0f, 1.0f)},
118     {Vector3(1.0f, -1.0f, -1.0f)},
119     {Vector3(1.0f, -1.0f, -1.0f)},
120     {Vector3(-1.0f, -1.0f, 1.0f)},
121     {Vector3(1.0f, -1.0f, 1.0f)}};
122
123   Dali::Shader       shaderSkybox  = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
124   Dali::VertexBuffer vertexBuffer  = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
125   vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
126
127   Dali::Geometry skyboxGeometry = Geometry::New();
128   skyboxGeometry.AddVertexBuffer(vertexBuffer);
129   skyboxGeometry.SetType(Geometry::TRIANGLES);
130
131   Dali::Texture    skyboxTexture   = Dali::Scene3D::Loader::LoadCubeMap(skyboxUrl);
132   Dali::TextureSet skyboxTextures = TextureSet::New();
133   skyboxTextures.SetTexture(0, skyboxTexture);
134
135   Dali::Renderer skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
136   skyboxRenderer.SetTextures(skyboxTextures);
137   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
138   // Enables the depth test.
139   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
140   // The fragment shader will run only is those pixels that have the max depth value.
141   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
142
143   Dali::Actor skyboxActor = Actor::New();
144   skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
145   skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
146   skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
147   skyboxActor.AddRenderer(skyboxRenderer);
148   return skyboxActor;
149 }
150
151 } // anonymous namespace
152
153 SceneView::SceneView()
154 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
155   mWindowOrientation(DEFAULT_ORIENTATION),
156   mSkybox(),
157   mSkyboxOrientation(Quaternion()),
158   mSkyboxIntensity(1.0f)
159 {
160 }
161
162 SceneView::~SceneView() = default;
163
164 Dali::Scene3D::SceneView SceneView::New()
165 {
166   SceneView* impl = new SceneView();
167
168   Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
169
170   // Second-phase init of the implementation
171   // This can only be done after the CustomActor connection has been made...
172   impl->Initialize();
173
174   return handle;
175 }
176
177 void SceneView::AddCamera(CameraActor camera)
178 {
179   if(camera)
180   {
181     if(mCameras.empty())
182     {
183       UpdateCamera(camera);
184     }
185     mCameras.push_back(camera);
186   }
187 }
188
189 void SceneView::RemoveCamera(CameraActor camera)
190 {
191   if(camera == mDefaultCamera)
192   {
193     DALI_LOG_ERROR("Default Camera cannot removed.\n");
194     return;
195   }
196
197   if(camera)
198   {
199     for(uint32_t i = 0; i < mCameras.size(); ++i)
200     {
201       if(mCameras[i] == camera)
202       {
203         mCameras.erase(mCameras.begin() + i);
204         break;
205       }
206     }
207
208     if(mSelectedCamera == camera)
209     {
210       CameraActor newCurrentCamera = *mCameras.begin();
211       UpdateCamera(newCurrentCamera);
212     }
213   }
214 }
215
216 uint32_t SceneView::GetCameraCount() const
217 {
218   return mCameras.size();
219 }
220
221 CameraActor SceneView::GetSelectedCamera() const
222 {
223   return mSelectedCamera;
224 }
225
226 CameraActor SceneView::GetCamera(uint32_t index) const
227 {
228   if(index < mCameras.size())
229   {
230     return mCameras[index];
231   }
232   DALI_LOG_ERROR("Input index is out of bounds\n");
233   return CameraActor();
234 }
235
236 CameraActor SceneView::GetCamera(const std::string& name) const
237 {
238   CameraActor returnCamera;
239   for(auto&& camera : mCameras)
240   {
241     if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
242     {
243       returnCamera = camera;
244       break;
245     }
246   }
247   return returnCamera;
248 }
249
250 void SceneView::SelectCamera(uint32_t index)
251 {
252   UpdateCamera(GetCamera(index));
253 }
254
255 void SceneView::SelectCamera(const std::string& name)
256 {
257   UpdateCamera(GetCamera(name));
258 }
259
260 void SceneView::RegisterModel(Scene3D::Model model)
261 {
262   if(model)
263   {
264     model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
265     mModels.push_back(model);
266   }
267 }
268
269 void SceneView::UnregisterModel(Scene3D::Model model)
270 {
271   if(model)
272   {
273     for(uint32_t i = 0; i < mModels.size(); ++i)
274     {
275       if(mModels[i] == model)
276       {
277         mModels.erase(mModels.begin() + i);
278         break;
279       }
280     }
281   }
282 }
283
284 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
285 {
286   mIBLResourceReady      = false;
287   Texture diffuseTexture = Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl);
288   if(diffuseTexture)
289   {
290     Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specularUrl);
291     if(specularTexture)
292     {
293       mDiffuseTexture  = diffuseTexture;
294       mSpecularTexture = specularTexture;
295       mIblScaleFactor  = scaleFactor;
296
297       for(auto&& model : mModels)
298       {
299         if(model)
300         {
301           model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
302         }
303       }
304     }
305   }
306   mIBLResourceReady = true;
307   if(IsResourceReady())
308   {
309     Control::SetResourceReady(false);
310   }
311 }
312
313 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
314 {
315   mIblScaleFactor = scaleFactor;
316   for(auto&& model : mModels)
317   {
318     if(model)
319     {
320       model.SetImageBasedLightScaleFactor(scaleFactor);
321     }
322   }
323 }
324
325 float SceneView::GetImageBasedLightScaleFactor() const
326 {
327   return mIblScaleFactor;
328 }
329
330 void SceneView::UseFramebuffer(bool useFramebuffer)
331 {
332   if(mUseFrameBuffer != useFramebuffer)
333   {
334     mUseFrameBuffer = useFramebuffer;
335     UpdateRenderTask();
336   }
337 }
338
339 bool SceneView::IsUsingFramebuffer() const
340 {
341   return mUseFrameBuffer;
342 }
343
344 void SceneView::SetSkybox(const std::string& skyboxUrl)
345 {
346   mSkyboxResourceReady = false;
347   if(mSkybox)
348   {
349     mSkybox.Unparent();
350     mSkybox.Reset();
351   }
352   mSkybox = CreateSkybox(skyboxUrl);
353   SetSkyboxIntensity(mSkyboxIntensity);
354   SetSkyboxOrientation(mSkyboxOrientation);
355   if(mRootLayer)
356   {
357     mRootLayer.Add(mSkybox);
358   }
359
360   mSkyboxResourceReady = true;
361   if(IsResourceReady())
362   {
363     Control::SetResourceReady(false);
364   }
365 }
366
367 void SceneView::SetSkyboxIntensity(float intensity)
368 {
369   mSkyboxIntensity = intensity;
370   if(intensity < 0)
371   {
372     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
373     mSkyboxIntensity = 0.0f;
374   }
375
376   if(mSkybox)
377   {
378     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
379   }
380 }
381
382 float SceneView::GetSkyboxIntensity() const
383 {
384   return mSkyboxIntensity;
385 }
386
387 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
388 {
389   mSkyboxOrientation = orientation;
390   if(mSkybox)
391   {
392     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
393   }
394 }
395
396 Quaternion SceneView::GetSkyboxOrientation() const
397 {
398   return mSkyboxOrientation;
399 }
400
401 ///////////////////////////////////////////////////////////
402 //
403 // Private methods
404 //
405
406 void SceneView::OnSceneConnection(int depth)
407 {
408   UpdateRenderTask();
409
410   Window window = DevelWindow::Get(Self());
411   if(window)
412   {
413     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
414   }
415
416   Control::OnSceneConnection(depth);
417 }
418
419 void SceneView::OnSceneDisconnection()
420 {
421   mModels.clear();
422
423   Window window = DevelWindow::Get(Self());
424   if(window)
425   {
426     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
427   }
428
429   Control::OnSceneDisconnection();
430 }
431
432 void SceneView::OnInitialize()
433 {
434   Actor self = Self();
435   mRootLayer = Layer::New();
436   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
437   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
438   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
439   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
440   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
441   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
442   self.Add(mRootLayer);
443
444   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
445   mRenderTask             = taskList.CreateTask();
446   mRenderTask.SetSourceActor(mRootLayer);
447   mRenderTask.SetExclusive(true);
448   mRenderTask.SetInputEnabled(true);
449   mRenderTask.SetCullMode(false);
450   mRenderTask.SetScreenToFrameBufferMappingActor(Self());
451
452   mDefaultCamera = Dali::CameraActor::New();
453   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
454   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
455   mDefaultCamera.SetNearClippingPlane(1.0f);
456   AddCamera(mDefaultCamera);
457   UpdateCamera(mDefaultCamera);
458 }
459
460 void SceneView::OnChildAdd(Actor& child)
461 {
462   if(child != mRootLayer)
463   {
464     mRootLayer.Add(child);
465   }
466   Control::OnChildAdd(child);
467 }
468
469 void SceneView::OnChildRemove(Actor& child)
470 {
471   mRootLayer.Remove(child);
472   Control::OnChildRemove(child);
473 }
474
475 float SceneView::GetHeightForWidth(float width)
476 {
477   Extents padding;
478   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
479   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
480 }
481
482 float SceneView::GetWidthForHeight(float height)
483 {
484   Extents padding;
485   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
486   return Control::GetWidthForHeight(height) + padding.start + padding.end;
487 }
488
489 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
490 {
491   Control::OnRelayout(size, container);
492   // Change canvas size of camera actor.
493   UpdateRenderTask();
494 }
495
496 bool SceneView::IsResourceReady() const
497 {
498   return mIBLResourceReady & mSkyboxResourceReady;
499 }
500
501 void SceneView::UpdateCamera(CameraActor camera)
502 {
503   if(camera)
504   {
505     if(mSelectedCamera && mSelectedCamera.GetParent())
506     {
507       mSelectedCamera.Unparent();
508     }
509     mRootLayer.Add(camera);
510   }
511
512   mSelectedCamera = camera;
513   UpdateRenderTask();
514 }
515
516 void SceneView::UpdateRenderTask()
517 {
518   if(mRenderTask)
519   {
520     if(mSelectedCamera != mRenderTask.GetCameraActor())
521     {
522       mRenderTask.SetCameraActor(mSelectedCamera);
523     }
524
525     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
526     const float aspectRatio = size.width / size.height;
527     mSelectedCamera.SetAspectRatio(aspectRatio);
528     const bool projectionVertical = mSelectedCamera.GetProperty<int>(Dali::DevelCameraActor::Property::PROJECTION_DIRECTION) == Dali::DevelCameraActor::VERTICAL;
529
530     // if projectionVertical, Top / Bottom is +-ve to keep consistency with orthographic values
531     // else, Left / Right is +-ve to keep consistency with orthographic values
532     const float orthographicSize = DALI_LIKELY(projectionVertical) ? mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE] : mSelectedCamera[Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE];
533     const float halfHeight       = DALI_LIKELY(projectionVertical) ? orthographicSize : orthographicSize / aspectRatio;
534     const float halfWidth        = DALI_LIKELY(projectionVertical) ? orthographicSize * aspectRatio : orthographicSize;
535
536     mSelectedCamera[Dali::CameraActor::Property::LEFT_PLANE_DISTANCE]   = -halfWidth;
537     mSelectedCamera[Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE]  = halfWidth;
538     mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE]    = halfHeight;
539     mSelectedCamera[Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE] = -halfHeight;
540
541     if(mUseFrameBuffer)
542     {
543       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
544       if(!currentFrameBuffer ||
545          currentFrameBuffer.GetColorTexture().GetWidth() != size.width ||
546          currentFrameBuffer.GetColorTexture().GetHeight() != size.height)
547       {
548         mRenderTask.ResetViewportGuideActor();
549         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
550
551         // create offscreen buffer of new size to render our child actors to
552         mTexture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
553         mRenderTarget = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
554         mRenderTarget.AttachColorTexture(mTexture);
555         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mRenderTarget, 0u);
556
557         Property::Map imagePropertyMap;
558         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
559         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
560         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
561         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
562         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
563
564         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
565
566         mRenderTask.SetFrameBuffer(mRenderTarget);
567         mRenderTask.SetClearEnabled(true);
568         mRenderTask.SetClearColor(Color::TRANSPARENT);
569       }
570     }
571     else
572     {
573       mRenderTask.SetViewportGuideActor(Self());
574       if(mRenderTask.GetFrameBuffer())
575       {
576         FrameBuffer framebuffer;
577         mRenderTask.SetFrameBuffer(framebuffer);
578         mRenderTask.SetClearEnabled(false);
579
580         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
581
582         mVisual.Reset();
583         mRenderTarget.Reset();
584         mTexture.Reset();
585       }
586     }
587
588     RotateCamera();
589   }
590 }
591
592 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
593 {
594   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
595   RotateCamera();
596 }
597
598 void SceneView::RotateCamera()
599 {
600   if(mUseFrameBuffer)
601   {
602     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
603   }
604   else
605   {
606     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
607   }
608 }
609
610 } // namespace Internal
611 } // namespace Scene3D
612 } // namespace Dali