2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using System.Runtime.InteropServices;
20 using System.ComponentModel;
22 using Tizen.NUI.Binding;
23 using Tizen.NUI.BaseComponents;
25 namespace Tizen.NUI.Scene3D
28 /// SceneView is a Class to show multiple 3D objects in a single 2D screen.
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.
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.
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.
42 /// SceneView also provides multiple Camera and one of them can be used to render 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.
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: AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance.
50 /// The Camera's FieldOfView is vertical fov. The horizontal fov is updated internally according to the SceneView size.
52 /// The <see cref="SetImageBasedLightSource(string, string, float)"/> method sets the same IBL to all Model objects added to the SceneView.
53 /// For the IBL, two cube map textures(diffuse and specular) are required.
54 /// SceneView supports 4 types layout for Cube Map: Vertical/Horizontal Cross layouts, and Vertical/Horizontal Array layouts.
55 /// And also, ktx format with cube map is supported.
56 /// If a model already has an IBL, it is batch overridden with the IBL of the SceneView.
57 /// If the SceneView has IBL, the IBL of newly added models is also overridden.
59 /// The IBL textures start to be loaded asynchronously when <see cref="SetImageBasedLightSource(string, string, float)"/> method is called.
60 /// ResourcesLoaded signal notifies that the loading of the IBL resources have been completed.
62 /// If FBO is used, the rendering result of SceneView is drawn on the FBO and it is mapped on the plane of the SceneView.
63 /// It could decreases performance slightly, but it is useful to show SceneView according to the rendering order with other Views.
65 /// And since SceneView is a View, it can be placed together with other 2D UI components in the NUI window.
67 /// <since_tizen> 10 </since_tizen>
68 public class SceneView : View
70 private bool inCameraTransition = false;
71 private Animation cameraTransition;
72 private string skyboxUrl;
74 internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
79 /// Create an initialized SceneView.
81 /// <since_tizen> 10 </since_tizen>
82 public SceneView() : this(Interop.SceneView.SceneNew(), true)
84 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
90 /// <param name="sceneView">The source object.</param>
91 /// <since_tizen> 10 </since_tizen>
92 public SceneView(SceneView sceneView) : this(Interop.SceneView.NewScene(SceneView.getCPtr(sceneView)), true)
94 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
98 /// Assignment operator.
100 /// <param name="sceneView">Handle to an object.</param>
101 /// <returns>Reference to this.</returns>
102 internal SceneView Assign(SceneView sceneView)
104 SceneView ret = new SceneView(Interop.SceneView.SceneAssign(SwigCPtr, SceneView.getCPtr(sceneView)), false);
105 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
110 /// Set/Get the ImageBasedLight ScaleFactor.
111 /// Scale factor controls light source intensity in [0.0f, 1.0f]
113 /// <since_tizen> 10 </since_tizen>
114 public float ImageBasedLightScaleFactor
118 SetImageBasedLightScaleFactor(value);
122 return GetImageBasedLightScaleFactor();
127 /// Set/Get the UseFramebuffer.
128 /// If this property is true, rendering result of SceneView is drawn on FBO and it is mapping on this SceneView plane.
129 /// If this property is false, each item in SceneView is rendered on window directly.
130 /// Default is false.
133 /// If UseFramebuffer is true, it could decrease performance but entire rendering order is satisfied.
134 /// If UseFramebuffer is false, the performance becomes better but SceneView is rendered on the top of the other 2D components regardless tree order.
136 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
137 [EditorBrowsable(EditorBrowsableState.Never)]
138 public bool UseFramebuffer
142 SetUseFramebuffer(value);
146 return IsUsingFramebuffer();
151 /// Set/Get SkyboxUrl.
152 /// If SkyboxUrl is set, the cube map image is loaded and skybox is attached on scene.
153 /// Skybox texture is asynchronously loaded. When loading is finished, ResourcesLoaded is emitted.
155 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
156 [EditorBrowsable(EditorBrowsableState.Never)]
157 public string SkyboxUrl
170 /// Set/Get Skybox intensity.
171 /// The skybox intensity is multiplied to the color of skybox texture.
172 /// Default value is 1.0f.
174 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
175 [EditorBrowsable(EditorBrowsableState.Never)]
176 public float SkyboxIntensity
180 SetSkyboxIntensity(value);
184 return GetSkyboxIntensity();
189 /// Set/Get angle of orientation of the skybox.
190 /// If orientation is set, the skybox will be rotate by the Radian orientation along YAxis.
191 /// Default value is 0.0f.
193 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
194 [EditorBrowsable(EditorBrowsableState.Never)]
195 public Rotation SkyboxOrientation
199 SetSkyboxOrientation(value);
203 return GetSkyboxOrientation();
208 /// Adds a Camera to the SceneView at the end of the camera list of SceneView.
209 /// The Camera can be used as a selected camera to render the scene by using <see cref="SelectCamera(uint)"/> or <see cref="SelectCamera(string)"/>
211 /// <param name="camera">Camera added on this SceneView.</param>
213 /// Some properties of the Camera will be change depending on the Size of this SceneView.
214 /// Those properties are as follows:
215 /// AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance.
217 /// The FieldOfView of Camera is for vertical fov.
218 /// When the size of the SceneView is changed, the vertical fov is maintained
219 /// and the horizontal fov is automatically calculated according to the SceneView's AspectRatio.
221 /// <since_tizen> 10 </since_tizen>
222 public void AddCamera(Camera camera)
226 Interop.SceneView.AddCamera(SwigCPtr, camera.SwigCPtr);
227 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
232 /// Removes a Camera from this SceneView.
233 /// If removed Camera is selected Camera,
234 /// first camera in the list becomes the selected Camera.
236 /// <param name="camera"> camera Camera to be removed from this Camera.</param>
238 /// When Camera.Dispose() is called, the NUI object is disposed, but camera information is maintained internally.
239 /// Therefore, even if Camera.Dispose() is called, RemoveCamera() or RemoveCamera() methods can be used.
240 /// If RemoveCamera() is called too, all information is deleted together.
242 /// <since_tizen> 10 </since_tizen>
243 public void RemoveCamera(Camera camera)
247 Interop.SceneView.RemoveCamera(SwigCPtr, camera.SwigCPtr);
248 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
253 /// Retrieves the number of cameras.
255 /// <returns>The number of Cameras.</returns>
256 /// <since_tizen> 10 </since_tizen>
257 public uint GetCameraCount()
259 uint count = Interop.SceneView.GetCameraCount(SwigCPtr);
260 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
265 /// Retrieves a Camera of the index.
267 /// <param name="index"> Index of Camera to be retrieved.</param>
268 /// <returns>Camera of the index.</returns>
269 /// <since_tizen> 10 </since_tizen>
270 public Camera GetCamera(uint index)
272 global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, index);
273 Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
276 // Register new camera into Registry.
277 camera = new Camera(cPtr, true);
281 // We found matched NUI camera. Reduce cPtr reference count.
282 HandleRef handle = new HandleRef(this, cPtr);
283 Interop.Camera.DeleteCameraProperty(handle);
284 handle = new HandleRef(null, IntPtr.Zero);
286 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
291 /// Retrieves a Camera of the input name.
293 /// <param name="name"> string keyword of Camera to be retrieved.</param>
294 /// <returns>Camera that has the name as a View.Name property</returns>
295 /// <since_tizen> 10 </since_tizen>
296 public Camera GetCamera(string name)
298 global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, name);
299 Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
302 // Register new camera into Registry.
303 camera = new Camera(cPtr, true);
307 // We found matched NUI camera. Reduce cPtr reference count.
308 HandleRef handle = new HandleRef(this, cPtr);
309 Interop.Camera.DeleteCameraProperty(handle);
310 handle = new HandleRef(null, IntPtr.Zero);
312 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
317 /// Makes SceneView use a Camera of index as a selected camera.
319 /// <param name="index"> Index of Camera to be used as a selected camera.</param>
320 /// <since_tizen> 10 </since_tizen>
321 public void SelectCamera(uint index)
323 if(inCameraTransition)
327 Interop.SceneView.SelectCamera(SwigCPtr, index);
328 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
332 /// Makes SceneView use a Camera of a name as a selected camera.
334 /// <param name="name"> string keyword of Camera to be used as a selected camera.</param>
335 /// <since_tizen> 10 </since_tizen>
336 public void SelectCamera(string name)
338 if(inCameraTransition)
342 Interop.SceneView.SelectCamera(SwigCPtr, name);
343 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
347 /// Starts camera transition from currently selected camera to a camera of index.
348 /// Camera Position, Orientation and FieldOfView are smoothly animated.
351 /// The selected camera is switched when the transition is started.
352 /// During camera transition, Selected Camera cannot be changed by using SelectCamera() or CameraTransition() method.
354 /// <param name="index"> Index of destination Camera of Camera transition.</param>
355 /// <param name="durationMilliSeconds">The duration in milliseconds.</param>
356 /// <param name="alphaFunction">The alpha function to apply.</param>
357 /// <since_tizen> 10 </since_tizen>
358 public void CameraTransition(uint index, int durationMilliSeconds, AlphaFunction alphaFunction = null)
360 if(inCameraTransition)
364 Camera source = GetSelectedCamera();
366 Camera destination = GetSelectedCamera();
367 CameraTransition(source, destination, durationMilliSeconds, alphaFunction);
369 destination.Dispose();
373 /// Starts camera transition from currently selected camera to a camera of input name.
374 /// Camera Position, Orientation and FieldOfView are smoothly animated.
377 /// The selected camera is switched when the transition is started.
378 /// During camera transition, Selected Camera cannot be changed by using SelectCamera() or CameraTransition() method.
380 /// <param name="name"> string keyword of destination Camera of Camera transition.</param>
381 /// <param name="durationMilliSeconds">The duration in milliseconds.</param>
382 /// <param name="alphaFunction">The alpha function to apply.</param>
383 /// <since_tizen> 10 </since_tizen>
384 public void CameraTransition(string name, int durationMilliSeconds, AlphaFunction alphaFunction = null)
386 if(inCameraTransition)
390 Camera source = GetSelectedCamera();
392 Camera destination = GetSelectedCamera();
393 CameraTransition(source, destination, durationMilliSeconds, alphaFunction);
395 destination.Dispose();
399 /// Retrieves selected Camera.
401 /// <returns> Camera currently used in SceneView as a selected Camera.</returns>
402 /// <since_tizen> 10 </since_tizen>
403 public Camera GetSelectedCamera()
405 global::System.IntPtr cPtr = Interop.SceneView.GetSelectedCamera(SwigCPtr);
406 Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
409 // Register new camera into Registry.
410 camera = new Camera(cPtr, true);
414 // We found matched NUI camera. Reduce cPtr reference count.
415 HandleRef handle = new HandleRef(this, cPtr);
416 Interop.Camera.DeleteCameraProperty(handle);
417 handle = new HandleRef(null, IntPtr.Zero);
419 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
424 /// Changes Image Based Light as the input textures.
426 /// <param name="diffuseUrl">The path of Cube map image that can be used as a diffuse IBL source.</param>
427 /// <param name="specularUrl">The path of Cube map image that can be used as a specular IBL source.</param>
428 /// <param name="scaleFactor">Scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f.</param>
430 /// http://tizen.org/privilege/mediastorage for local files in media storage.
431 /// http://tizen.org/privilege/externalstorage for local files in external storage.
433 /// <since_tizen> 10 </since_tizen>
434 public void SetImageBasedLightSource(string diffuseUrl, string specularUrl, float scaleFactor = 1.0f)
436 Interop.SceneView.SetImageBasedLightSource(SwigCPtr, diffuseUrl, specularUrl, scaleFactor);
437 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
440 internal void SetUseFramebuffer(bool useFramebuffer)
442 Interop.SceneView.UseFramebuffer(SwigCPtr, useFramebuffer);
443 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
446 internal bool IsUsingFramebuffer()
448 bool result = Interop.SceneView.IsUsingFramebuffer(SwigCPtr);
449 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
454 /// Set the ImageBasedLight ScaleFactor.
456 /// <param name="scaleFactor">Scale factor that controls light source intensity in [0.0f, 1.0f].</param>
457 private void SetImageBasedLightScaleFactor(float scaleFactor)
459 Interop.SceneView.SetImageBasedLightScaleFactor(SwigCPtr, scaleFactor);
460 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
464 /// Get the ImageBasedLight ScaleFactor.
466 /// <returns>ImageBasedLightScaleFactor that controls light source intensity.</returns>
467 private float GetImageBasedLightScaleFactor()
469 float scaleFactor = Interop.SceneView.GetImageBasedLightScaleFactor(SwigCPtr);
470 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
475 /// Set the Skybox from cube map image.
476 /// Skybox texture is asynchronously loaded. When loading is finished, ResourcesLoaded is emitted.
478 /// <param name="skyboxUrl">Cube map image url for skybox.</param>
479 private void SetSkybox(string skyboxUrl)
481 this.skyboxUrl = skyboxUrl;
482 Interop.SceneView.SetSkybox(SwigCPtr, skyboxUrl);
483 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
487 /// Sets Skybox intensity.
488 /// The skybox intensity is multiplied to the color of skybox texture.
489 /// Default value is 1.0f.
491 /// <param name="intensity">Intensity value to be multiplied to the cube map color.</param>
492 private void SetSkyboxIntensity(float intensity)
494 Interop.SceneView.SetSkyboxIntensity(SwigCPtr, intensity);
495 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
499 /// Gets Skybox intensity.
500 /// Default value is 1.0f.
502 /// <returns>skybox intensity.</returns>
503 private float GetSkyboxIntensity()
505 float intensity = Interop.SceneView.GetSkyboxIntensity(SwigCPtr);
506 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
511 /// Sets orientation of the skybox.
513 /// <param name="orientation">Rotation angle of the skybox along YAxis.</param>
514 private void SetSkyboxOrientation(Rotation orientation)
516 Interop.SceneView.SetSkyboxOrientation(SwigCPtr, Rotation.getCPtr(orientation));
517 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
521 /// Gets Skybox orientation.
523 /// <returns>skybox orientation.</returns>
524 private Rotation GetSkyboxOrientation()
526 global::System.IntPtr cPtr = Interop.SceneView.GetSkyboxOrientation(SwigCPtr);
527 Rotation ret = (cPtr == global::System.IntPtr.Zero) ? null : new Rotation(cPtr, false);
528 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
532 private void CameraTransition(Camera sourceCamera, Camera destinationCamera, int durationMilliSeconds, AlphaFunction alphaFunction)
534 inCameraTransition = true;
536 Position sourcePosition = sourceCamera.Position;
537 Rotation sourceOrientation = sourceCamera.Orientation;
538 Radian sourceFieldOfView = sourceCamera.FieldOfView;
540 Position destinationPosition = destinationCamera.Position;
541 Rotation destinationOrientation = destinationCamera.Orientation;
542 Radian destinationFieldOfView = destinationCamera.FieldOfView;
544 // If ProjectionDirection is not equal, match the value.
545 if (sourceCamera.ProjectionDirection != destinationCamera.ProjectionDirection)
547 float aspect = destinationCamera.AspectRatio;
548 if (destinationCamera.ProjectionDirection == Camera.ProjectionDirectionType.Vertical)
550 sourceFieldOfView = Camera.ConvertFovFromHorizontalToVertical(aspect, sourceFieldOfView);
554 sourceFieldOfView = Camera.ConvertFovFromVerticalToHorizontal(aspect, sourceFieldOfView);
558 cameraTransition = new Animation(durationMilliSeconds);
560 KeyFrames positionKeyFrames = new KeyFrames();
561 positionKeyFrames.Add(0.0f, sourcePosition);
562 positionKeyFrames.Add(1.0f, destinationPosition);
564 KeyFrames orientationKeyFrames = new KeyFrames();
565 orientationKeyFrames.Add(0.0f, sourceOrientation);
566 orientationKeyFrames.Add(1.0f, destinationOrientation);
568 KeyFrames fieldOfViewKeyFrames = new KeyFrames();
569 fieldOfViewKeyFrames.Add(0.0f, sourceFieldOfView.ConvertToFloat());
570 fieldOfViewKeyFrames.Add(1.0f, destinationFieldOfView.ConvertToFloat());
572 cameraTransition.AnimateBetween(destinationCamera, "Position", positionKeyFrames, Animation.Interpolation.Linear, alphaFunction);
573 cameraTransition.AnimateBetween(destinationCamera, "Orientation", orientationKeyFrames, Animation.Interpolation.Linear, alphaFunction);
574 cameraTransition.AnimateBetween(destinationCamera, "FieldOfView", fieldOfViewKeyFrames, Animation.Interpolation.Linear, alphaFunction);
576 cameraTransition.Finished += (s, e) =>
578 inCameraTransition = false;
580 cameraTransition.Play();
582 sourceFieldOfView.Dispose();
583 positionKeyFrames.Dispose();
584 orientationKeyFrames.Dispose();
585 orientationKeyFrames.Dispose();
589 /// Release swigCPtr.
591 // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
592 [EditorBrowsable(EditorBrowsableState.Never)]
593 protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr)
595 Interop.SceneView.DeleteScene(swigCPtr);