Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NUI.Scene3D] Add Capture for SceneView #6592

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ internal static partial class SceneView

[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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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
{
/// <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;
}
}
}
105 changes: 105 additions & 0 deletions src/Tizen.NUI.Scene3D/src/public/Controls/SceneView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,16 @@ namespace Tizen.NUI.Scene3D
/// <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)
{
}
Expand All @@ -94,6 +101,29 @@ public SceneView(SceneView sceneView) : this(Interop.SceneView.NewScene(SceneVie
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>
Expand All @@ -106,6 +136,38 @@ internal SceneView Assign(SceneView sceneView)
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>
Expand Down Expand Up @@ -469,6 +531,39 @@ public void ResetResolution()
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
}
bshsqa marked this conversation as resolved.
Show resolved Hide resolved
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);
Expand Down Expand Up @@ -611,6 +706,16 @@ private void CameraTransition(Camera sourceCamera, Camera destinationCamera, int
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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Binary file not shown.
Loading