[NUI] Add Camera Transition in SceneView
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Scene3D / src / public / Controls / SceneView.cs
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 using System;
19 using System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using Tizen.NUI;
22 using Tizen.NUI.Binding;
23 using Tizen.NUI.BaseComponents;
24
25 namespace Tizen.NUI.Scene3D
26 {
27     /// <summary>
28     /// SceneView is a Class to show multiple 3D objects in a single 2D sreen.
29     /// Each SceneView has its own 3D space, and 3D objects added to SceneView are positioned in the space.
30     /// SceneView uses left-handed coordinate system same as NUI. X as right, Y as down, and Z as forward.
31     ///
32     /// SceneView has internal root container to control inner rendering process like depth test.
33     /// When a View is added to the SceneView with <see cref="View.Add(View)"/> method, it is actually added on the root container.
34     /// Therefore, the added Views exist in the sub tree of SceneView, but are not direct children.
35     /// The sub tree of Views will be rendered with the SceneView's own Camera.
36     ///
37     /// SceneView has one built-in camera by default.
38     /// The default Camera is not removed by using <see cref="RemoveCamera(Camera)"/> method.
39     /// <see cref="GetCamera(uint)"/> method with index "0" returns the default camera,
40     /// and the minimum value returned by <see cref="GetCameraCount()"/> method is 1.
41     ///
42     /// SceneView also provides multiple Camera and one of them can be used to render the multiple objects.
43     /// <see cref="AddCamera(Camera)"/>, <see cref="RemoveCamera(Camera)"/>, <see cref="GetCamera(uint)"/>,
44     /// and <see cref="SelectCamera(uint)"/> are methods to manage Cameras of the SceneView.
45     /// User can place multiple cameras in a scene to display the entire scene or to display individual objects.
46     /// User can use the <see cref="SelectCamera(uint)"/> method to select the currently required camera.
47     ///
48     /// When the SceneView's size changes, some camera properties that depend on its size may also change.
49     /// The changing properties are as follows: ProjectionMode, AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance.
50     /// Position, Near/FarPlaneDistance, and FieldOfView are maintained even if the size of the SceneView is changed.
51     /// The Camera's FieldOfView is vertical fov. The horizontal fov is updated internally according to the SceneView size.
52     ///
53     /// The <see cref="SetImageBasedLightSource(string, string, float)"/> method sets the same IBL to all Model objects added to the SceneView.
54     /// For the IBL, two cube map textures(diffuse and specular) are required.
55     /// SceneView supports 4 types layout for Cube Map: Vertical/Horizontal Cross layouts, and Vertical/Horizontal Array layouts.
56     /// And also, ktx format with cube map is supported.
57     /// If a model already has an IBL, it is batch overridden with the IBL of the SceneView.
58     /// If the SceneView has IBL, the IBL of newly added models is also overridden.
59     ///
60     /// The IBL textures start to be loaded asynchronously when <see cref="SetImageBasedLightSource(string, string, float)"/> method is called.
61     /// ResourcesLoaded signal notifies that the loading of the IBL resources have been completed.
62     ///
63     /// SceneView provides an option to use FBO for rendering result with <see cref="UseFramebuffer"/> property.
64     /// If it is false, SceneView is always drawn in the form of a rectangle on the default window surface directly.
65     /// It improves performance, but the SceneView is always drawn on top of other 2D objects regardless of rendering order.
66     ///
67     /// If FBO is used, the rendering result of SceneView is drawn on the FBO and it is mapped on the plane of the SceneView.
68     /// It could decreases performance slightly, but it is useful to show SceneView according to the rendering order with other Views.
69     ///
70     /// And since SceneView is a View, it can be placed together with other 2D UI components in the NUI window.
71     /// </summary>
72     /// <code>
73     /// </code>
74     // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
75     [EditorBrowsable(EditorBrowsableState.Never)]
76     public class SceneView : View
77     {
78         private bool inCameraTransition = false;
79         private Animation cameraTransition;
80
81         internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
82         {
83         }
84
85         /// <summary>
86         /// Create an initialized SceneView.
87         /// </summary>
88         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
89         [EditorBrowsable(EditorBrowsableState.Never)]
90         public SceneView() : this(Interop.SceneView.SceneNew(), true)
91         {
92             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
93         }
94
95         /// <summary>
96         /// Copy constructor.
97         /// </summary>
98         /// <param name="sceneView">Handle to an object.</param>
99         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
100         [EditorBrowsable(EditorBrowsableState.Never)]
101         public SceneView(SceneView sceneView) : this(Interop.SceneView.NewScene(SceneView.getCPtr(sceneView)), true)
102         {
103             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
104         }
105
106         /// <summary>
107         /// Assignment operator.
108         /// </summary>
109         /// <param name="sceneView">Handle to an object.</param>
110         /// <returns>Reference to this.</returns>
111         internal SceneView Assign(SceneView sceneView)
112         {
113             SceneView ret = new SceneView(Interop.SceneView.SceneAssign(SwigCPtr, SceneView.getCPtr(sceneView)), false);
114             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
115             return ret;
116         }
117
118         /// <summary>
119         /// Set/Get the ImageBasedLight ScaleFactor.
120         /// Scale factor controls light source intensity in [0.0f, 1.0f]
121         /// </summary>
122         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
123         [EditorBrowsable(EditorBrowsableState.Never)]
124         public float ImageBasedLightScaleFactor
125         {
126             set
127             {
128                 SetImageBasedLightScaleFactor(value);
129             }
130             get
131             {
132                 return GetImageBasedLightScaleFactor();
133             }
134         }
135
136         /// <summary>
137         /// Set/Get the UseFramebuffer.
138         /// If this property is true, rendering result of SceneView is drawn on FBO and it is mapping on this SceneView plane.
139         /// If this property is false, each item in SceneView is rendered on window directly.
140         /// Default is false.
141         /// </summary>
142         /// <remarks>
143         /// If useFramebuffer is true, it could decrease performance but entire rendering order is satisfied.
144         /// If useFramebuffer is false, the performance becomes better but SceneView is rendered on the top of the other 2D components regardless tree order.
145         /// </remarks>
146         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
147         [EditorBrowsable(EditorBrowsableState.Never)]
148         public bool UseFramebuffer
149         {
150             set
151             {
152                 SetUseFramebuffer(value);
153             }
154             get
155             {
156                 return IsUsingFramebuffer();
157             }
158         }
159
160         /// <summary>
161         /// Adds a Camera to the SceneView
162         /// The Camera can be used as a selected camera to render the scene by using <see cref="SelectCamera(uint)"/> or <see cref="SelectCamera(string)"/>
163         /// </summary>
164         /// <param name="camera">Camera added on this SceneView.</param>
165         /// <remarks>
166         /// Some properties of the Camera will be change depending on the Size of this SceneView.
167         /// Those properties are as follows:
168         /// aspectRatio, nearPlaneDistance, farPlaneDistance, leftPlaneDistance, rightPlaneDistance, topPlaneDistance, and bottomPlaneDistance.
169         ///
170         /// The FieldOfView of Camera is for vertical fov.
171         /// When the size of the SceneView is changed, the vertical fov is maintained
172         /// and the horizontal fov is automatically calculated according to the SceneView's aspect ratio.
173         /// </remarks>
174         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
175         [EditorBrowsable(EditorBrowsableState.Never)]
176         public void AddCamera(Camera camera)
177         {
178             if(camera != null)
179             {
180                 Interop.SceneView.AddCamera(SwigCPtr, camera.SwigCPtr);
181                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
182             }
183         }
184
185         /// <summary>
186         /// Removes a Camera from this SceneView.
187         /// If removed Camera is selected Camera,
188         /// first camera in the list is set to selected Camera.
189         /// </summary>
190         /// <param name="camera"> camera Camera to be removed from this Camera.</param>
191         /// <remarks>
192         /// Camera.Dispose() don't automatically release memory. We should call this API if we want to release memory.
193         /// We cannot remove default camera. If we try to remove default camera, ignored.
194         /// </remarks>
195         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
196         [EditorBrowsable(EditorBrowsableState.Never)]
197         public void RemoveCamera(Camera camera)
198         {
199             if(camera != null)
200             {
201                 Interop.SceneView.RemoveCamera(SwigCPtr, camera.SwigCPtr);
202                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
203             }
204         }
205
206         /// <summary>
207         /// Retrieves the number of cameras.
208         /// </summary>
209         /// <returns>The number of Cameras.</returns>
210         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
211         [EditorBrowsable(EditorBrowsableState.Never)]
212         public uint GetCameraCount()
213         {
214             uint count = Interop.SceneView.GetCameraCount(SwigCPtr);
215             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
216             return count;
217         }
218
219         /// <summary>
220         /// Retrieves a Camera of the index.
221         /// </summary>
222         /// <param name="index"> Index of Camera to be retrieved.</param>
223         /// <returns>Camera of the index.</returns>
224         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
225         [EditorBrowsable(EditorBrowsableState.Never)]
226         public Camera GetCamera(uint index)
227         {
228             global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, index);
229             Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
230             if(camera == null)
231             {
232                 // Register new camera into Registry.
233                 camera = new Camera(cPtr, true);
234             }
235             else
236             {
237                 // We found matched NUI camera. Reduce cPtr reference count.
238                 HandleRef handle = new HandleRef(this, cPtr);
239                 Interop.Camera.DeleteCameraProperty(handle);
240                 handle = new HandleRef(null, IntPtr.Zero);
241             }
242             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
243             return camera;
244         }
245
246         /// <summary>
247         /// Retrieves a Camera of the index.
248         /// </summary>
249         /// <param name="name"> string keyword of Camera to be retrieved.</param>
250         /// <returns>Camera that has the name as a View.Name property</returns>
251         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
252         [EditorBrowsable(EditorBrowsableState.Never)]
253         public Camera GetCamera(string name)
254         {
255             global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, name);
256             Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
257             if(camera == null)
258             {
259                 // Register new camera into Registry.
260                 camera = new Camera(cPtr, true);
261             }
262             else
263             {
264                 // We found matched NUI camera. Reduce cPtr reference count.
265                 HandleRef handle = new HandleRef(this, cPtr);
266                 Interop.Camera.DeleteCameraProperty(handle);
267                 handle = new HandleRef(null, IntPtr.Zero);
268             }
269             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
270             return camera;
271         }
272
273         /// <summary>
274         /// Makes SceneView use a Camera of index as a selected camera.
275         /// </summary>
276         /// <param name="index"> Index of Camera to be used as a selected camera.</param>
277         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
278         [EditorBrowsable(EditorBrowsableState.Never)]
279         public void SelectCamera(uint index)
280         {
281             if(inCameraTransition)
282             {
283                 return;
284             }
285             Interop.SceneView.SelectCamera(SwigCPtr, index);
286             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
287         }
288
289         /// <summary>
290         /// Makes SceneView use a Camera of a name as a selected camera.
291         /// </summary>
292         /// <param name="name"> string keyword of Camera to be used as a selected camera.</param>
293         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
294         [EditorBrowsable(EditorBrowsableState.Never)]
295         public void SelectCamera(string name)
296         {
297             if(inCameraTransition)
298             {
299                 return;
300             }
301             Interop.SceneView.SelectCamera(SwigCPtr, name);
302             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
303         }
304
305         /// <summary>
306         /// Start camera transition from currently selected camera to a camera of index.
307         /// Camera Position and Orientation is smoothly animated.
308         /// </summary>
309         /// <remarks>
310         /// The selected camera is switched when the transition is started.
311         /// During camera transition, Selected Camera cannot be changed by using SelectCamera() or CameraTransition() method.
312         /// </remarks>
313         /// <param name="index"> Index of destination Camera of Camera transition.</param>
314         /// <param name="durationMilliSeconds">The duration in milliseconds.</param>
315         /// <param name="alphaFunction">The alpha function to apply.</param>
316         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
317         [EditorBrowsable(EditorBrowsableState.Never)]
318         public void CameraTransition(uint index, int durationMilliSeconds, AlphaFunction alphaFunction = null)
319         {
320             if(inCameraTransition)
321             {
322                 return;
323             }
324             Camera source = GetSelectedCamera();
325             SelectCamera(index);
326             Camera destination = GetSelectedCamera();
327             CameraTransition(source, destination, durationMilliSeconds, alphaFunction);
328         }
329
330         /// <summary>
331         /// Start camera transition from currently selected camera to a camera of input name.
332         /// Camera Position and Orientation is smoothly animated.
333         /// </summary>
334         /// <remarks>
335         /// The selected camera is switched when the transition is started.
336         /// During camera transition, Selected Camera cannot be changed by using SelectCamera() or CameraTransition() method.
337         /// </remarks>
338         /// <param name="name"> string keyword of destination Camera of Camera transition.</param>
339         /// <param name="durationMilliSeconds">The duration in milliseconds.</param>
340         /// <param name="alphaFunction">The alpha function to apply.</param>
341         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
342         [EditorBrowsable(EditorBrowsableState.Never)]
343         public void CameraTransition(string name, int durationMilliSeconds, AlphaFunction alphaFunction = null)
344         {
345             if(inCameraTransition)
346             {
347                 return;
348             }
349             Camera source = GetSelectedCamera();
350             SelectCamera(name);
351             Camera destination = GetSelectedCamera();
352             CameraTransition(source, destination, durationMilliSeconds, alphaFunction);
353         }
354
355         /// <summary>
356         /// Retrieves selected Camera.
357         /// </summary>
358         /// <returns> Camera currently used in SceneView as a selected Camera.</returns>
359         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
360         [EditorBrowsable(EditorBrowsableState.Never)]
361         public Camera GetSelectedCamera()
362         {
363             global::System.IntPtr cPtr = Interop.SceneView.GetSelectedCamera(SwigCPtr);
364             Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
365             if(camera == null)
366             {
367                 // Register new camera into Registry.
368                 camera = new Camera(cPtr, true);
369             }
370             else
371             {
372                 // We found matched NUI camera. Reduce cPtr reference count.
373                 HandleRef handle = new HandleRef(this, cPtr);
374                 Interop.Camera.DeleteCameraProperty(handle);
375                 handle = new HandleRef(null, IntPtr.Zero);
376             }
377             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
378             return camera;
379         }
380
381         /// <summary>
382         /// Changes Image Based Light as the input textures.
383         /// </summary>
384         /// <param name="diffuseUrl">The path of Cube map image that can be used as a diffuse IBL source.</param>
385         /// <param name="specularUrl">The path of Cube map image that can be used as a specular IBL source.</param>
386         /// <param name="scaleFactor">Scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f.</param>
387         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
388         [EditorBrowsable(EditorBrowsableState.Never)]
389         public void SetImageBasedLightSource(string diffuseUrl, string specularUrl, float scaleFactor = 1.0f)
390         {
391             Interop.SceneView.SetImageBasedLightSource(SwigCPtr, diffuseUrl, specularUrl, scaleFactor);
392             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
393         }
394
395         internal void SetUseFramebuffer(bool useFramebuffer)
396         {
397             Interop.SceneView.UseFramebuffer(SwigCPtr, useFramebuffer);
398             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
399         }
400
401         internal bool IsUsingFramebuffer()
402         {
403             bool result = Interop.SceneView.IsUsingFramebuffer(SwigCPtr);
404             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
405             return result;
406         }
407
408         /// <summary>
409         /// Set the ImageBasedLight ScaleFactor.
410         /// </summary>
411         /// <param name="scaleFactor">Scale factor that controls light source intensity in [0.0f, 1.0f].</param>
412         private void SetImageBasedLightScaleFactor(float scaleFactor)
413         {
414             Interop.SceneView.SetImageBasedLightScaleFactor(SwigCPtr, scaleFactor);
415             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
416         }
417
418         /// <summary>
419         /// Get the ImageBasedLight ScaleFactor.
420         /// </summary>
421         /// <returns>ImageBasedLightScaleFactor that controls light source intensity.</returns>
422         private float GetImageBasedLightScaleFactor()
423         {
424             float scaleFactor = Interop.SceneView.GetImageBasedLightScaleFactor(SwigCPtr);
425             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
426             return scaleFactor;
427         }
428
429         private void CameraTransition(Camera sourceCamera, Camera destinationCamera, int durationMilliSeconds, AlphaFunction alphaFunction)
430         {
431             inCameraTransition = true;
432
433             Position sourcePosition = sourceCamera.Position;
434             Rotation sourceOrientation = sourceCamera.Orientation;
435
436             Position destinationPosition = destinationCamera.Position;
437             Rotation destinationOrientation = destinationCamera.Orientation;
438
439             cameraTransition = new Animation(durationMilliSeconds);
440             KeyFrames positionKeyFrames = new KeyFrames();
441             positionKeyFrames.Add(0.0f, sourcePosition);
442             positionKeyFrames.Add(1.0f, destinationPosition);
443             KeyFrames orientationKeyFrames = new KeyFrames();
444             orientationKeyFrames.Add(0.0f, sourceOrientation);
445             orientationKeyFrames.Add(1.0f, destinationOrientation);
446             cameraTransition.AnimateBetween(destinationCamera, "Position", positionKeyFrames, Animation.Interpolation.Linear, alphaFunction);
447             cameraTransition.AnimateBetween(destinationCamera, "Orientation", orientationKeyFrames, Animation.Interpolation.Linear, alphaFunction);
448
449             cameraTransition.Finished += (s, e) =>
450             {
451                 inCameraTransition = false;
452             };
453             cameraTransition.Play();
454         }
455
456         /// <summary>
457         /// Release swigCPtr.
458         /// </summary>
459         // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
460         [EditorBrowsable(EditorBrowsableState.Never)]
461         protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr)
462         {
463             Interop.SceneView.DeleteScene(swigCPtr);
464         }
465     }
466 }