/*
* Copyright(c) 2022 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Tizen.NUI;
using Tizen.NUI.Binding;
using Tizen.NUI.BaseComponents;
namespace Tizen.NUI.Scene3D
{
///
/// SceneView is a Class to show multiple 3D objects in a single 2D screen.
/// Each SceneView has its own 3D space, and 3D objects added to SceneView are positioned in the space.
/// SceneView uses left-handed coordinate system same as NUI. X as right, Y as down, and Z as forward.
///
/// SceneView has internal root container to control inner rendering process like depth test.
/// When a View is added to the SceneView with method, it is actually added on the root container.
/// Therefore, the added Views exist in the sub tree of SceneView, but are not direct children.
/// The sub tree of Views will be rendered with the SceneView's own Camera.
///
/// SceneView has one built-in camera by default.
/// The default Camera is not removed by using method.
/// method with index "0" returns the default camera,
/// and the minimum value returned by method is 1.
///
/// SceneView also provides multiple Camera and one of them can be used to render multiple objects.
/// , , ,
/// and are methods to manage Cameras of the SceneView.
/// User can place multiple cameras in a scene to display the entire scene or to display individual objects.
/// User can use the method to select the currently required camera.
///
/// When the SceneView's size changes, some camera properties that depend on its size may also change.
/// The changing properties are as follows: AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance.
/// The Camera's FieldOfView is vertical fov. The horizontal fov is updated internally according to the SceneView size.
///
/// The method sets the same IBL to all Model objects added to the SceneView.
/// For the IBL, two cube map textures(diffuse and specular) are required.
/// SceneView supports 4 types layout for Cube Map: Vertical/Horizontal Cross layouts, and Vertical/Horizontal Array layouts.
/// And also, ktx format with cube map is supported.
/// If a model already has an IBL, it is batch overridden with the IBL of the SceneView.
/// If the SceneView has IBL, the IBL of newly added models is also overridden.
///
/// The IBL textures start to be loaded asynchronously when method is called.
/// ResourcesLoaded signal notifies that the loading of the IBL resources have been completed.
///
/// If FBO is used, the rendering result of SceneView is drawn on the FBO and it is mapped on the plane of the SceneView.
/// It could decreases performance slightly, but it is useful to show SceneView according to the rendering order with other Views.
///
/// And since SceneView is a View, it can be placed together with other 2D UI components in the NUI window.
///
/// 10
public class SceneView : View
{
private bool inCameraTransition = false;
private Animation cameraTransition;
private string skyboxUrl;
internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
{
}
internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, true, cRegister)
{
}
///
/// Create an initialized SceneView.
///
/// 10
public SceneView() : this(Interop.SceneView.SceneNew(), true)
{
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Copy constructor.
///
/// The source object.
/// 10
public SceneView(SceneView sceneView) : this(Interop.SceneView.NewScene(SceneView.getCPtr(sceneView)), true, false)
{
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Assignment operator.
///
/// Handle to an object.
/// Reference to this.
internal SceneView Assign(SceneView sceneView)
{
SceneView ret = new SceneView(Interop.SceneView.SceneAssign(SwigCPtr, SceneView.getCPtr(sceneView)), false);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return ret;
}
///
/// An event emitted when Camera Transition is finished.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler CameraTransitionFinished;
///
/// Set/Get the ImageBasedLight ScaleFactor.
/// Scale factor controls light source intensity in [0.0f, 1.0f]
///
/// 10
public float ImageBasedLightScaleFactor
{
set
{
SetImageBasedLightScaleFactor(value);
}
get
{
return GetImageBasedLightScaleFactor();
}
}
///
/// Set/Get the UseFramebuffer.
/// If this property is true, rendering result of SceneView is drawn on FBO and it is mapping on this SceneView plane.
/// If this property is false, each item in SceneView is rendered on window directly.
/// Default is false.
///
///
/// If UseFramebuffer is true, it could decrease performance but entire rendering order is satisfied.
/// If UseFramebuffer is false, the performance becomes better but SceneView is rendered on the top of the other 2D components regardless tree order.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public bool UseFramebuffer
{
set
{
SetUseFramebuffer(value);
}
get
{
return IsUsingFramebuffer();
}
}
///
/// Set/Get the Framebuffer's MultiSamplingLevel.
/// Only has effects if UseFramebuffer is true, and Framebuffer MultiSampling is supported.
/// Default is 0.
///
///
/// Getter didn't consider Framebuffer MultiSampling is supported or not.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public uint FramebufferMultiSamplingLevel
{
set
{
SetFramebufferMultiSamplingLevel(value);
}
get
{
return GetFramebufferMultiSamplingLevel();
}
}
///
/// Set/Get SkyboxUrl.
/// If SkyboxUrl is set, the cube map image is loaded and skybox is attached on scene.
/// Skybox texture is asynchronously loaded. When loading is finished, ResourcesLoaded is emitted.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public string SkyboxUrl
{
set
{
SetSkybox(value);
}
get
{
return skyboxUrl;
}
}
///
/// Set/Get Skybox intensity.
/// The skybox intensity is multiplied to the color of skybox texture.
/// Default value is 1.0f.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public float SkyboxIntensity
{
set
{
SetSkyboxIntensity(value);
}
get
{
return GetSkyboxIntensity();
}
}
///
/// Set/Get angle of orientation of the skybox.
/// If orientation is set, the skybox will be rotate by the Radian orientation along YAxis.
/// Default value is 0.0f.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public Rotation SkyboxOrientation
{
set
{
SetSkyboxOrientation(value);
}
get
{
return GetSkyboxOrientation();
}
}
///
/// Adds a Camera to the SceneView at the end of the camera list of SceneView.
/// The Camera can be used as a selected camera to render the scene by using or
///
/// Camera added on this SceneView.
///
/// Some properties of the Camera will be change depending on the Size of this SceneView.
/// Those properties are as follows:
/// AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance.
///
/// The FieldOfView of Camera is for vertical fov.
/// When the size of the SceneView is changed, the vertical fov is maintained
/// and the horizontal fov is automatically calculated according to the SceneView's AspectRatio.
///
/// 10
public void AddCamera(Camera camera)
{
if (camera != null)
{
Interop.SceneView.AddCamera(SwigCPtr, camera.SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
}
///
/// Removes a Camera from this SceneView.
/// If removed Camera is selected Camera,
/// first camera in the list becomes the selected Camera.
///
/// camera Camera to be removed from this Camera.
///
/// When Camera.Dispose() is called, the NUI object is disposed, but camera information is maintained internally.
/// Therefore, even if Camera.Dispose() is called, RemoveCamera() or RemoveCamera() methods can be used.
/// If RemoveCamera() is called too, all information is deleted together.
///
/// 10
public void RemoveCamera(Camera camera)
{
if (camera != null)
{
Interop.SceneView.RemoveCamera(SwigCPtr, camera.SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
}
///
/// Retrieves the number of cameras.
///
/// The number of Cameras.
/// 10
public uint GetCameraCount()
{
uint count = Interop.SceneView.GetCameraCount(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return count;
}
///
/// Retrieves a Camera of the index.
///
/// Index of Camera to be retrieved.
/// Camera of the index.
/// 10
public Camera GetCamera(uint index)
{
global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, index);
Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
if (camera == null)
{
// Register new camera into Registry.
camera = new Camera(cPtr, true);
}
else
{
// We found matched NUI camera. Reduce cPtr reference count.
HandleRef handle = new HandleRef(this, cPtr);
Interop.Camera.DeleteCameraProperty(handle);
handle = new HandleRef(null, IntPtr.Zero);
}
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return camera;
}
///
/// Retrieves a Camera of the input name.
///
/// string keyword of Camera to be retrieved.
/// Camera that has the name as a View.Name property
/// 10
public Camera GetCamera(string name)
{
global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, name);
Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
if (camera == null)
{
// Register new camera into Registry.
camera = new Camera(cPtr, true);
}
else
{
// We found matched NUI camera. Reduce cPtr reference count.
HandleRef handle = new HandleRef(this, cPtr);
Interop.Camera.DeleteCameraProperty(handle);
handle = new HandleRef(null, IntPtr.Zero);
}
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return camera;
}
///
/// Makes SceneView use a Camera of index as a selected camera.
///
/// Index of Camera to be used as a selected camera.
/// 10
public void SelectCamera(uint index)
{
if (inCameraTransition)
{
return;
}
this.GetSelectedCamera()?.Unparent();
Interop.SceneView.SelectCamera(SwigCPtr, index);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Makes SceneView use a Camera of a name as a selected camera.
///
/// string keyword of Camera to be used as a selected camera.
/// 10
public void SelectCamera(string name)
{
if (inCameraTransition)
{
return;
}
this.GetSelectedCamera()?.Unparent();
Interop.SceneView.SelectCamera(SwigCPtr, name);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Starts camera transition from currently selected camera to a camera of index.
/// Camera Position, Orientation and FieldOfView are smoothly animated.
///
///
/// The selected camera is switched to the Camera of the index when the transition is started.
/// During camera transition, Selected Camera should not be changed by using SelectCamera() or CameraTransition() method.
/// During camera transition, Camera properties of Selected Camera should not be changed.
///
/// Index of destination Camera of Camera transition.
/// The duration in milliseconds.
/// The alpha function to apply.
/// 10
[SuppressMessage("Microsoft.Design", "CA2000: Dispose objects before losing scope", Justification = "The ownership of camera object is not owned by this class.")]
public void CameraTransition(uint index, int durationMilliSeconds, AlphaFunction alphaFunction = null)
{
if (inCameraTransition || GetSelectedCamera() == GetCamera(index))
{
return;
}
Camera source = GetSelectedCamera();
SelectCamera(index);
Camera destination = GetSelectedCamera();
CameraTransition(source, destination, durationMilliSeconds, alphaFunction);
}
///
/// Starts camera transition from currently selected camera to a camera of input name.
/// Camera Position, Orientation and FieldOfView are smoothly animated.
///
///
/// The selected camera is switched to the Camera of the input name when the transition is started.
/// During camera transition, Selected Camera should not be changed by using SelectCamera() or CameraTransition() method.
/// During camera transition, Camera properties of Selected Camera should not be changed.
///
/// string keyword of destination Camera of Camera transition.
/// The duration in milliseconds.
/// The alpha function to apply.
/// 10
[SuppressMessage("Microsoft.Design", "CA2000: Dispose objects before losing scope", Justification = "The ownership of camera object is not owned by this class.")]
public void CameraTransition(string name, int durationMilliSeconds, AlphaFunction alphaFunction = null)
{
if (inCameraTransition || GetSelectedCamera() == GetCamera(name))
{
return;
}
Camera source = GetSelectedCamera();
SelectCamera(name);
Camera destination = GetSelectedCamera();
CameraTransition(source, destination, durationMilliSeconds, alphaFunction);
}
///
/// Retrieves selected Camera.
///
/// Camera currently used in SceneView as a selected Camera.
/// 10
public Camera GetSelectedCamera()
{
global::System.IntPtr cPtr = Interop.SceneView.GetSelectedCamera(SwigCPtr);
Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera;
if (camera == null)
{
// Register new camera into Registry.
camera = new Camera(cPtr, true);
}
else
{
// We found matched NUI camera. Reduce cPtr reference count.
HandleRef handle = new HandleRef(this, cPtr);
Interop.Camera.DeleteCameraProperty(handle);
handle = new HandleRef(null, IntPtr.Zero);
}
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return camera;
}
///
/// Changes Image Based Light as the input textures.
///
/// The path of Cube map image that can be used as a diffuse IBL source.
/// The path of Cube map image that can be used as a specular IBL source.
/// Scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f.
///
/// http://tizen.org/privilege/mediastorage for local files in media storage.
/// http://tizen.org/privilege/externalstorage for local files in external storage.
///
/// 10
public void SetImageBasedLightSource(string diffuseUrl, string specularUrl, float scaleFactor = 1.0f)
{
Interop.SceneView.SetImageBasedLightSource(SwigCPtr, diffuseUrl, specularUrl, scaleFactor);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Add Lights to this SceneView.
///
/// The light what we want to add
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public void AddLight(Light light)
{
Interop.SceneView.AddLight(SwigCPtr, Light.getCPtr(light));
NDalicPINVOKE.ThrowExceptionIfExists();
}
///
/// Remove Lights from this SceneView.
///
/// The light what we want to remove
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public void RemoveLight(Light light)
{
Interop.SceneView.RemoveLight(SwigCPtr, Light.getCPtr(light));
NDalicPINVOKE.ThrowExceptionIfExists();
}
///
/// Sets SceneView's resolution manually.
///
/// The input width.
/// The input height.
///
/// This manual resolution is only available when the SceneView uses FBO for rendering by using FBO (UseFrameBuffer is true).
/// If the aspect ratio of input width/height is different with SceneView's aspect ratio, the rendered result is stretched to fill SceneView's area.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public void SetResolution(uint width, uint height)
{
Interop.SceneView.SetResolution(SwigCPtr, width, height);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Retrieves width of resolution of the SceneView.
///
///
/// If the SceneView not uses FBO, this method returns SceneView's width.
///
/// Camera currently used in SceneView as a selected Camera.
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public uint GetResolutionWidth()
{
uint result = Interop.SceneView.GetResolutionWidth(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return result;
}
///
/// Retrieves height of resolution of the SceneView.
///
///
/// If the SceneView not uses FBO, this method returns SceneView's height.
///
/// Camera currently used in SceneView as a selected Camera.
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public uint GetResolutionHeight()
{
uint result = Interop.SceneView.GetResolutionHeight(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return result;
}
///
/// Resets SceneView's resolution to the current size of SceneView.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public void ResetResolution()
{
Interop.SceneView.ResetResolution(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
internal void SetUseFramebuffer(bool useFramebuffer)
{
Interop.SceneView.UseFramebuffer(SwigCPtr, useFramebuffer);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
internal bool IsUsingFramebuffer()
{
bool result = Interop.SceneView.IsUsingFramebuffer(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return result;
}
internal void SetFramebufferMultiSamplingLevel(uint multiSamplingLevel)
{
Interop.SceneView.SetFramebufferMultiSamplingLevel(SwigCPtr, multiSamplingLevel);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
internal uint GetFramebufferMultiSamplingLevel()
{
uint result = Interop.SceneView.GetFramebufferMultiSamplingLevel(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return result;
}
///
/// Set the ImageBasedLight ScaleFactor.
///
/// Scale factor that controls light source intensity in [0.0f, 1.0f].
private void SetImageBasedLightScaleFactor(float scaleFactor)
{
Interop.SceneView.SetImageBasedLightScaleFactor(SwigCPtr, scaleFactor);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Get the ImageBasedLight ScaleFactor.
///
/// ImageBasedLightScaleFactor that controls light source intensity.
private float GetImageBasedLightScaleFactor()
{
float scaleFactor = Interop.SceneView.GetImageBasedLightScaleFactor(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return scaleFactor;
}
///
/// Set the Skybox from cube map image.
/// Skybox texture is asynchronously loaded. When loading is finished, ResourcesLoaded is emitted.
///
/// Cube map image url for skybox.
private void SetSkybox(string skyboxUrl)
{
this.skyboxUrl = skyboxUrl;
Interop.SceneView.SetSkybox(SwigCPtr, skyboxUrl);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Sets Skybox intensity.
/// The skybox intensity is multiplied to the color of skybox texture.
/// Default value is 1.0f.
///
/// Intensity value to be multiplied to the cube map color.
private void SetSkyboxIntensity(float intensity)
{
Interop.SceneView.SetSkyboxIntensity(SwigCPtr, intensity);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Gets Skybox intensity.
/// Default value is 1.0f.
///
/// skybox intensity.
private float GetSkyboxIntensity()
{
float intensity = Interop.SceneView.GetSkyboxIntensity(SwigCPtr);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return intensity;
}
///
/// Sets orientation of the skybox.
///
/// Rotation angle of the skybox along YAxis.
private void SetSkyboxOrientation(Rotation orientation)
{
Interop.SceneView.SetSkyboxOrientation(SwigCPtr, Rotation.getCPtr(orientation));
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
///
/// Gets Skybox orientation.
///
/// skybox orientation.
private Rotation GetSkyboxOrientation()
{
global::System.IntPtr cPtr = Interop.SceneView.GetSkyboxOrientation(SwigCPtr);
Rotation ret = (cPtr == global::System.IntPtr.Zero) ? null : new Rotation(cPtr, true);
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
return ret;
}
private void CameraTransition(Camera sourceCamera, Camera destinationCamera, int durationMilliSeconds, AlphaFunction alphaFunction)
{
inCameraTransition = true;
Position sourcePosition = sourceCamera.Position;
Rotation sourceOrientation = sourceCamera.Orientation;
Position destinationPosition = destinationCamera.Position;
Rotation destinationOrientation = destinationCamera.Orientation;
cameraTransition = new Animation(durationMilliSeconds);
KeyFrames positionKeyFrames = new KeyFrames();
positionKeyFrames.Add(0.0f, sourcePosition);
positionKeyFrames.Add(1.0f, destinationPosition);
KeyFrames orientationKeyFrames = new KeyFrames();
orientationKeyFrames.Add(0.0f, sourceOrientation);
orientationKeyFrames.Add(1.0f, destinationOrientation);
cameraTransition.AnimateBetween(destinationCamera, "Position", positionKeyFrames, Animation.Interpolation.Linear, alphaFunction);
cameraTransition.AnimateBetween(destinationCamera, "Orientation", orientationKeyFrames, Animation.Interpolation.Linear, alphaFunction);
if (destinationCamera.ProjectionMode == Camera.ProjectionModeType.Perspective)
{
Radian sourceFieldOfView = sourceCamera.FieldOfView;
Radian destinationFieldOfView = destinationCamera.FieldOfView;
// If ProjectionDirection is not equal, match the value.
if (sourceCamera.ProjectionDirection != destinationCamera.ProjectionDirection)
{
float aspect = destinationCamera.AspectRatio;
if (destinationCamera.ProjectionDirection == Camera.ProjectionDirectionType.Vertical)
{
Camera.ConvertFovFromHorizontalToVertical(aspect, ref sourceFieldOfView);
}
else
{
Camera.ConvertFovFromVerticalToHorizontal(aspect, ref sourceFieldOfView);
}
}
KeyFrames fieldOfViewKeyFrames = new KeyFrames();
fieldOfViewKeyFrames.Add(0.0f, sourceFieldOfView.ConvertToFloat());
fieldOfViewKeyFrames.Add(1.0f, destinationFieldOfView.ConvertToFloat());
cameraTransition.AnimateBetween(destinationCamera, "FieldOfView", fieldOfViewKeyFrames, Animation.Interpolation.Linear, alphaFunction);
sourceFieldOfView.Dispose();
destinationFieldOfView.Dispose();
fieldOfViewKeyFrames.Dispose();
}
else
{
float sourceOrthographicSize = sourceCamera.OrthographicSize;
float destinationOrthographicSize = destinationCamera.OrthographicSize;
// If ProjectionDirection is not equal, match the value.
if (sourceCamera.ProjectionDirection != destinationCamera.ProjectionDirection)
{
float aspect = destinationCamera.AspectRatio;
if (destinationCamera.ProjectionDirection == Camera.ProjectionDirectionType.Vertical)
{
sourceOrthographicSize = sourceOrthographicSize / aspect;
}
else
{
sourceOrthographicSize = sourceOrthographicSize * aspect;
}
}
KeyFrames orthographicSizeKeyFrames = new KeyFrames();
orthographicSizeKeyFrames.Add(0.0f, sourceOrthographicSize);
orthographicSizeKeyFrames.Add(1.0f, destinationOrthographicSize);
cameraTransition.AnimateBetween(destinationCamera, "OrthographicSize", orthographicSizeKeyFrames, Animation.Interpolation.Linear, alphaFunction);
orthographicSizeKeyFrames.Dispose();
}
float destinationNearPlaneDistance = destinationCamera.NearPlaneDistance;
float destinationFarPlaneDistance = destinationCamera.FarPlaneDistance;
destinationCamera.NearPlaneDistance = Math.Min(sourceCamera.NearPlaneDistance, destinationCamera.NearPlaneDistance);
destinationCamera.FarPlaneDistance = Math.Max(sourceCamera.FarPlaneDistance, destinationCamera.FarPlaneDistance);
cameraTransition.Finished += (s, e) =>
{
this.GetSelectedCamera().NearPlaneDistance = destinationNearPlaneDistance;
this.GetSelectedCamera().FarPlaneDistance = destinationFarPlaneDistance;
inCameraTransition = false;
CameraTransitionFinished?.Invoke(this, EventArgs.Empty);
};
cameraTransition.Play();
positionKeyFrames.Dispose();
orientationKeyFrames.Dispose();
}
///
/// Release swigCPtr.
///
// This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr)
{
Interop.SceneView.DeleteScene(swigCPtr);
}
}
}