From: Seungho Baek Date: Tue, 13 Aug 2024 09:40:13 +0000 (+0900) Subject: [NUI.Scene3D] Add Capture for SceneView X-Git-Tag: submit/tizen_7.0/20250121.110757~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7d100a93d44c74863e0943e66672d77269a7bdb1;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI.Scene3D] Add Capture for SceneView Signed-off-by: Seungho Baek --- diff --git a/src/Tizen.NUI.Scene3D/src/internal/Interop/Interop.SceneView.cs b/src/Tizen.NUI.Scene3D/src/internal/Interop/Interop.SceneView.cs index 2923edc3f..f6638f8c0 100755 --- a/src/Tizen.NUI.Scene3D/src/internal/Interop/Interop.SceneView.cs +++ b/src/Tizen.NUI.Scene3D/src/internal/Interop/Interop.SceneView.cs @@ -96,6 +96,15 @@ namespace Tizen.NUI.Scene3D [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_GetFramebufferMultiSamplingLevel")] public static extern uint GetFramebufferMultiSamplingLevel(global::System.Runtime.InteropServices.HandleRef sceneView); + + [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_Capture")] + public static extern int Capture(global::System.Runtime.InteropServices.HandleRef sceneView, global::System.Runtime.InteropServices.HandleRef camera, global::System.Runtime.InteropServices.HandleRef size); + + [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_CaptureFinishedSignal_Connect")] + public static extern void CaptureFinishedConnect(global::System.Runtime.InteropServices.HandleRef actor, global::System.Runtime.InteropServices.HandleRef handler); + + [global::System.Runtime.InteropServices.DllImport(Libraries.Scene3D, EntryPoint = "CSharp_Dali_SceneView_CaptureFinishedSignal_Disconnect")] + public static extern void CaptureFinishedDisconnect(global::System.Runtime.InteropServices.HandleRef actor, global::System.Runtime.InteropServices.HandleRef handler); } } } diff --git a/src/Tizen.NUI.Scene3D/src/public/Controls/CaptureFinishedEventArgs.cs b/src/Tizen.NUI.Scene3D/src/public/Controls/CaptureFinishedEventArgs.cs new file mode 100644 index 000000000..588f9cefb --- /dev/null +++ b/src/Tizen.NUI.Scene3D/src/public/Controls/CaptureFinishedEventArgs.cs @@ -0,0 +1,48 @@ +/* + * Copyright(c) 2024 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.ComponentModel; + +namespace Tizen.NUI.Scene3D +{ + /// + /// Event arguments of SceneView capture finished event. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class CaptureFinishedEventArgs : EventArgs + { + /// + /// Integer ID of the capture request. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int CaptureId + { + get; set; + } + + /// + /// ImageUrl of the captured result + /// If the capture is failed, it is null. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ImageUrl CapturedImageUrl + { + get; set; + } + } +} diff --git a/src/Tizen.NUI.Scene3D/src/public/Controls/SceneView.cs b/src/Tizen.NUI.Scene3D/src/public/Controls/SceneView.cs index 27bfbdf95..1361e3971 100755 --- a/src/Tizen.NUI.Scene3D/src/public/Controls/SceneView.cs +++ b/src/Tizen.NUI.Scene3D/src/public/Controls/SceneView.cs @@ -68,9 +68,16 @@ namespace Tizen.NUI.Scene3D /// 10 public class SceneView : View { + private bool inCapture = false; private bool inCameraTransition = false; private Animation cameraTransition; + // CaptureFinishedEvent + private EventHandler captureFinishedEventHandler; + private CaptureFinishedEventCallbackType captureFinishedEventCallback; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void CaptureFinishedEventCallbackType(IntPtr data, int captureId, IntPtr capturedImageUrl); + internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn) { } @@ -94,6 +101,29 @@ namespace Tizen.NUI.Scene3D if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } + /// + /// Dispose Explicit or Implicit + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void Dispose(DisposeTypes type) + { + if (Disposed) + { + return; + } + + if (captureFinishedEventCallback != null) + { + NUILog.Debug($"[Dispose] captureFinishedEventCallback"); + Interop.SceneView.CaptureFinishedDisconnect(GetBaseHandleCPtrHandleRef, captureFinishedEventCallback.ToHandleRef(this)); + NDalicPINVOKE.ThrowExceptionIfExistsDebug(); + captureFinishedEventCallback = null; + } + LayoutCount = 0; + + base.Dispose(type); + } + /// /// Assignment operator. /// @@ -106,6 +136,38 @@ namespace Tizen.NUI.Scene3D return ret; } + + /// + /// An event emitted when Capture is finished. + /// If Capture is successed, CaptureFinishedEventArgs includes finished capture ID and ImageUrl of the captured image. + /// If Capture is failed, the ImageUrl is null. + /// + // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler CaptureFinished + { + add + { + if (captureFinishedEventHandler == null) + { + captureFinishedEventCallback = OnCaptureFinished; + Interop.SceneView.CaptureFinishedConnect(SwigCPtr, captureFinishedEventCallback.ToHandleRef(this)); + NDalicPINVOKE.ThrowExceptionIfExists(); + } + captureFinishedEventHandler += value; + } + remove + { + captureFinishedEventHandler -= value; + if (captureFinishedEventHandler == null && captureFinishedEventCallback != null) + { + Interop.SceneView.CaptureFinishedDisconnect(SwigCPtr, captureFinishedEventCallback.ToHandleRef(this)); + NDalicPINVOKE.ThrowExceptionIfExists(); + captureFinishedEventCallback = null; + } + } + } + /// /// An event emitted when Camera Transition is finished. /// @@ -469,6 +531,39 @@ namespace Tizen.NUI.Scene3D if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } + /// + /// Requests to capture this SceneView with the Camera. + /// + /// Camera to be used for capture. + /// captured size. + /// + /// The input camera should not be used for any other purpose during Capture. + /// The selected camera cannot be used for input camera. + /// The camera is required to be added in this SceneView. + /// If the SceneView is disconnected from Scene, the left capture request is canceled. + /// + /// capture id that id unique value to distinguish each request. + /// If capture is requested during previous capture, invalid index(-1) is returned. + // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) + [EditorBrowsable(EditorBrowsableState.Never)] + public int Capture(Scene3D.Camera camera, Vector2 size) + { + if(inCapture) + { + Tizen.Log.Error("NUI", "The previous capture request is not finished yet.\n"); + return -1; // invalid index + } + if(camera == null) + { + Tizen.Log.Error("NUI", "Invalid Camera is used.\n"); + return -1; // invalid index + } + inCapture = true; + int id = Interop.SceneView.Capture(SwigCPtr, camera.SwigCPtr, Vector2.getCPtr(size)); + if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); + return id; + } + internal void SetUseFramebuffer(bool useFramebuffer) { Interop.SceneView.UseFramebuffer(SwigCPtr, useFramebuffer); @@ -611,6 +706,16 @@ namespace Tizen.NUI.Scene3D positionKeyFrames.Dispose(); orientationKeyFrames.Dispose(); } + + // Callback for capture finished signal + private void OnCaptureFinished(IntPtr data, int captureId, IntPtr capturedImageUrl) + { + CaptureFinishedEventArgs e = new CaptureFinishedEventArgs(); + e.CaptureId = captureId; + e.CapturedImageUrl = new ImageUrl(capturedImageUrl, false); + captureFinishedEventHandler?.Invoke(this, e); + inCapture = false; // To prevent to request capture in the capture finished callback. + } /// /// Release swigCPtr. diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/Scene3DCaptureTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/Scene3DCaptureTest.cs new file mode 100755 index 000000000..a1f15860f --- /dev/null +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/Scene3DCaptureTest.cs @@ -0,0 +1,163 @@ +using System.Numerics; +using System.Reflection.Metadata.Ecma335; +using System.Threading.Tasks; +using global::System; +using Tizen.NUI; +using Tizen.NUI.BaseComponents; +using Tizen.NUI.Scene3D; + +namespace Tizen.NUI.Samples +{ + using log = Tizen.Log; + public class Scene3DCaptureTest : IExample + { + private Window window; + private SceneView sceneView; + private static readonly string resourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource; + private Tizen.NUI.Scene3D.Camera[] cameras; + private string[] cameraName; + private int cameraIndex; + int captureId; + ImageView imageView; + ImageUrl imageUrl; + bool inCapture = false; + + Animation rotAnimation; + public void Activate() + { + window = NUIApplication.GetDefaultWindow(); + Size2D windowSize = window.Size; + + sceneView = new SceneView() + { + Size = new Size(windowSize.Width, windowSize.Height), + PivotPoint = PivotPoint.TopLeft, + ParentOrigin = ParentOrigin.TopLeft, + PositionUsesPivotPoint = true, + BackgroundColor = new Color(0.85f, 0.85f, 0.85f, 1.0f), + UseFramebuffer = true, + }; + window.Add(sceneView); + + Light light = new Light() + { + Color = new Vector4(0.4f, 0.4f, 0.4f, 1.0f), + Position = new Vector3(-1.0f, 0.0f, 1.1f), + PositionUsesPivotPoint = true, + }; + light.LookAt(new Vector3(0.0f, 0.0f, 0.0f)); + sceneView.Add(light); + + cameras = new Scene3D.Camera[2]; + cameraName = new string[]{"camera1", "camera2"}; + Vector3[] cameraPosition = new Vector3[]{new Vector3(1.5f, 0.0f, 1.5f), new Vector3(-1.5f, -1.5f, 1.5f)}; + Vector3 modelPosition = new Vector3(-1.5f, 0.0f, 0.0f); + + cameraIndex = 0; + for(uint i = 0; i<2; ++i) + { + cameras[i] = new Scene3D.Camera() + { + Name = cameraName[i], + Position = cameraPosition[i], + NearPlaneDistance = 1.0f, + FarPlaneDistance = 10.0f, + }; + sceneView.AddCamera(cameras[i]); + } + cameras[1].FieldOfView = new Radian(new Degree(70.0f)); + + Model model = new Model(resourcePath + "models/BoxAnimated.glb") + { + PositionUsesPivotPoint = true, + Position = modelPosition, + Size = new Size(0.5f, 0.5f, 0.5f), + }; + sceneView.Add(model); + model.Add(cameras[0]); + sceneView.SelectCamera(cameraName[0]); + model.ResourcesLoaded += (s, e) => + { + SceneCapture(1); + }; + sceneView.Add(cameras[1]); + + cameras[0].LookAt(modelPosition); + cameras[1].LookAt(modelPosition); + + rotAnimation = new Animation(3000); + KeyFrames keyFrames = new KeyFrames(); + keyFrames.Add(0.0f, new Rotation(new Radian(new Degree(0.0f)), Vector3.YAxis)); + keyFrames.Add(0.25f, new Rotation(new Radian(new Degree(90.0f)), Vector3.YAxis)); + keyFrames.Add(0.5f, new Rotation(new Radian(new Degree(180.0f)), Vector3.YAxis)); + keyFrames.Add(0.75f, new Rotation(new Radian(new Degree(270.0f)), Vector3.YAxis)); + keyFrames.Add(1.0f, new Rotation(new Radian(new Degree(360.0f)), Vector3.YAxis)); + rotAnimation.AnimateBetween(model, "Orientation", keyFrames); + rotAnimation.Looping = true; + rotAnimation.Play(); + + + sceneView.CaptureFinished += (s, e) => + { + Tizen.Log.Error("NUI", $"Finished Capture ID : {e.CaptureId}\n"); + if(e.CapturedImageUrl == null) + { + Tizen.Log.Error("NUI", $"Capture Failed\n"); + return; + } + CreateImageView(e.CapturedImageUrl); + }; + + window.KeyEvent += WindowKeyEvent; + } + + private void WindowKeyEvent(object sender, Window.KeyEventArgs e) + { + if (e.Key.State == Key.StateType.Down) + { + if (e.Key.KeyPressedName == "1") + { + SceneCapture(1); + } + else + { + return; + } + } + } + + void SceneCapture(int captureCameraIndex) + { + captureId = sceneView.Capture(cameras[captureCameraIndex], new Vector2(300, 300)); + Tizen.Log.Error("NUI", $"Requestd Capture ID : {captureId}\n"); + } + + void CreateImageView(ImageUrl capturedImageUrl) + { + if (imageView != null) + { + imageView.Dispose(); + } + if (imageUrl != null) + { + imageUrl.Dispose(); + } + imageUrl = capturedImageUrl; + + imageView = new ImageView(imageUrl.ToString()) + { + Size = new Size(300, 300), + PositionUsesPivotPoint = true, + ParentOrigin = ParentOrigin.BottomLeft, + PivotPoint = PivotPoint.BottomLeft + }; + window.Add(imageView); + } + + public void Deactivate() + { + window.KeyEvent -= WindowKeyEvent; + sceneView?.Dispose(); + } + } +} \ No newline at end of file diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/models/BoxAnimated.glb b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/models/BoxAnimated.glb new file mode 100644 index 000000000..69481ec3c Binary files /dev/null and b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/res/models/BoxAnimated.glb differ