[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);
}
}
}
--- /dev/null
+/*
+ * 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
+{
+ /// <summary>
+ /// Event arguments of SceneView capture finished event.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class CaptureFinishedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Integer ID of the capture request.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int CaptureId
+ {
+ get; set;
+ }
+
+ /// <summary>
+ /// ImageUrl of the captured result
+ /// If the capture is failed, it is null.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ImageUrl CapturedImageUrl
+ {
+ get; set;
+ }
+ }
+}
/// <since_tizen> 10 </since_tizen>
public class SceneView : View
{
+ private bool inCapture = false;
private bool inCameraTransition = false;
private Animation cameraTransition;
+ // CaptureFinishedEvent
+ private EventHandler<CaptureFinishedEventArgs> 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)
{
}
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
+ /// <summary>
+ /// Dispose Explicit or Implicit
+ /// </summary>
+ [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);
+ }
+
/// <summary>
/// Assignment operator.
/// </summary>
return ret;
}
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event EventHandler<CaptureFinishedEventArgs> 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;
+ }
+ }
+ }
+
/// <summary>
/// An event emitted when Camera Transition is finished.
/// </summary>
if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
}
+ /// <summary>
+ /// Requests to capture this SceneView with the Camera.
+ /// </summary>
+ /// <param name="camera">Camera to be used for capture.</param>
+ /// <param name="size">captured size.</param>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ /// <returns> capture id that id unique value to distinguish each request.
+ /// If capture is requested during previous capture, invalid index(-1) is returned.</returns>
+ // 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);
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.
+ }
/// <summary>
/// Release swigCPtr.
--- /dev/null
+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