# Auto-generated from csapi-tizenfx.spec.in by makespec.sh
%define TIZEN_NET_API_VERSION 12
-%define TIZEN_NET_RPM_VERSION 12.0.0.18314+nui22324
-%define TIZEN_NET_NUGET_VERSION 12.0.0.18314
+%define TIZEN_NET_RPM_VERSION 12.0.0.999+nui22327
+%define TIZEN_NET_NUGET_VERSION 12.0.0.99999
%define DOTNET_ASSEMBLY_PATH /usr/share/dotnet.tizen/framework
%define DOTNET_ASSEMBLY_DUMMY_PATH %{DOTNET_ASSEMBLY_PATH}/ref
NUGET_VERSION=12.0.0.99999
# RPM Version Suffix
-RPM_VERSION_SUFFIX=nui22324
+RPM_VERSION_SUFFIX=nui22327
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
* limitations under the License.
*
*/
+
using System.ComponentModel;
using Tizen.NUI.Scene3D;
namespace Tizen.AIAvatar
{
+ /// <summary>
+ /// The AnimationInfo class manages animation data for an Avatar, including motion data and names. It is not meant to be directly edited by users or editors.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public class AnimationInfo
{
+ /// <summary>
+ /// Gets the motion data associated with this animation.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public MotionData MotionData { get; internal set; }
+ public MotionData MotionData { get; private set; }
+
+ /// <summary>
+ /// Gets the name of this animation.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public string MotionName { get; internal set; }
+ public string MotionName { get; private set; }
+ /// <summary>
+ /// Initializes a new instance of the AnimationInfo class with the specified motion data and name.
+ /// </summary>
+ /// <param name="motionData">TheThe motion data associated with this animation.</param>
+ /// <param name="motionName">The name of this animation.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
public AnimationInfo(MotionData motionData, string motionName)
{
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
namespace Tizen.AIAvatar
{
- /// <summary>
- ///
- /// </summary>
+ /// <summary>
+ /// This class provides arguments for handling avatar motion change events.
+ /// <member name = "Previous" > The previous state of the avatar's motion.</member>
+ /// <member name = "Current" > The current state of the avatar's motion.</member>
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public class AvatarMotionChangedEventArgs : EventArgs
{
+ /// <summary>
+ /// Initializes a new instance of the AvatarMotionChangedEventArgs class with the specified previous and current states.
+ /// </summary>
+ /// <param name="previous">The previous state of the avatar's motion.</param>
+ /// <param name="current">The current state of the avatar's motion.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
public AvatarMotionChangedEventArgs(AvatarMotionState previous, AvatarMotionState current)
{
/// <summary>
/// The previous state.
/// </summary>
- /// <since_tizen> 3 </since_tizen>
[EditorBrowsable(EditorBrowsableState.Never)]
public AvatarMotionState Previous
{
/// <summary>
/// The current state.
/// </summary>
- /// <since_tizen> 3 </since_tizen>
[EditorBrowsable(EditorBrowsableState.Never)]
public AvatarMotionState Current
{
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/// <summary>
/// Enumeration for the states.
/// </summary>
- /// <since_tizen> 3 </since_tizen>
[EditorBrowsable(EditorBrowsableState.Never)]
public enum AvatarMotionState
{
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
*/
using System;
-using System.ComponentModel;
using Tizen.NUI;
-using Tizen.NUI.Scene3D;
using static Tizen.AIAvatar.AIAvatar;
namespace Tizen.AIAvatar
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class EyeBlinker : AnimationModule
+ internal class EyeBlinker : IBlendShapeModule, IDisposable
{
+ private AvatarMotionState currentMotionState = AvatarMotionState.Unavailable;
+
+ private readonly Object motionChangedLock = new Object();
+ private event EventHandler<AvatarMotionChangedEventArgs> motionChanged;
+
private const int blinkIntervalMinimum = 800;
private const int blinkIntervalMaximum = 3000;
private Animation eyeAnimation;
private bool isPlaying = false;
private const int blinkDuration = 200;
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal EyeBlinker()
+ public AvatarMotionState CurrentMotionState
+ {
+ get
+ {
+ return currentMotionState;
+ }
+ set
+ {
+ if (currentMotionState == value)
+ {
+ return;
+ }
+ var preState = currentMotionState;
+ currentMotionState = value;
+ if (motionChanged != null)
+ {
+ motionChanged?.Invoke(this, new AvatarMotionChangedEventArgs(preState, currentMotionState));
+ }
+ }
+ }
+
+ public event EventHandler<AvatarMotionChangedEventArgs> MotionStateChanged
+ {
+ add
+ {
+ lock (motionChangedLock)
+ {
+ motionChanged += value;
+ }
+
+ }
+
+ remove
+ {
+ lock (motionChangedLock)
+ {
+ if (motionChanged == null)
+ {
+ Log.Error(LogTag, "Remove StateChanged Failed : motionChanged is null");
+ return;
+ }
+ motionChanged -= value;
+ }
+ }
+ }
+
+ public EyeBlinker()
{
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Init(Animation eyeAnimation)
+ public void Dispose()
+ {
+ DestroyAnimation();
+ }
+
+ public void Init(Animation eyeAnimation)
{
this.eyeAnimation = eyeAnimation;
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Play(IAnimationModuleData data)
+ public void Play()
{
//data
StartEyeBlink();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Stop()
+ public void Stop()
{
StopEyeBlink();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Pause()
+ public void Pause()
{
eyeAnimation?.Pause();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Destroy()
+ public void Destroy()
{
DestroyAnimation();
}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
*
*/
-using System.ComponentModel;
+using Tizen.NUI;
namespace Tizen.AIAvatar
{
- internal class BlendShapeValue
+ internal interface IBlendShapeModule
{
- internal string nodeName;
- internal BlendShapeType blendIndex;
- internal float blendValue;
+ public void Init(Animation animation);
+
+ public void Play();
+
+ public void Stop();
+
+ public void Pause();
+
+ public void Destroy();
}
+
}
*
*/
-using System.ComponentModel;
using Tizen.NUI;
using Tizen.NUI.Scene3D;
-
using static Tizen.AIAvatar.AIAvatar;
namespace Tizen.AIAvatar
internal class MotionPlayer
{
private Animation motionAnimation;
+ private EyeBlinker eyeBlinker;
+
internal Animation MotionAnimation { get => motionAnimation; private set => motionAnimation = value; }
internal MotionPlayer()
{
+ eyeBlinker = new EyeBlinker();
+
}
- /// <summary>
- /// Play avatar animation by AnimationInfo
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
internal void PlayAnimation(Animation motionAnimation, int duration = 3000, bool isLooping = false, int loopCount = 1)
{
ResetAnimations();
}
}
- /// <summary>
- /// Pause avatar animation
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
internal void PauseMotionAnimation()
{
MotionAnimation?.Pause();
}
- /// <summary>
- /// Stop avatar animation
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
internal void StopMotionAnimation()
{
MotionAnimation?.Stop();
}
+ internal void SetBlinkAnimation(Animation blinkerAnimation)
+ {
+ eyeBlinker?.Init(blinkerAnimation);
+ }
+
+ internal void StartEyeBlink()
+ {
+ eyeBlinker?.Play();
+ }
+
+ internal void PauseEyeBlink()
+ {
+ eyeBlinker?.Pause();
+ }
+
+
+ internal void StopEyeBlink()
+ {
+ eyeBlinker?.Stop();
+ }
+
+ internal void DestroyAnimations()
+ {
+ eyeBlinker?.Destroy();
+ }
+
private void ResetAnimations()
{
if (MotionAnimation != null)
MotionAnimation = null;
}
}
+
}
}
--- /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.ComponentModel;
+using Tizen.NUI.Scene3D;
+using Tizen.NUI;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+ /// <summary>
+ /// The Avatar class displays 3D avatars and provides easy access to their animations.
+ /// This class is a sub-class of the Model class which allows us to easily control the Avatar's animations.
+ /// Avatar also supports AR Emoji for humanoid-based 3D models.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class Avatar : Model
+ {
+ private AvatarProperties avatarProperties = new DefaultAvatarProperties();
+
+ private MotionPlayer motionPlayer;
+
+ /// <summary>
+ /// The AvatarProperties property gets or sets the AvatarProperties object containing various information about the Avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AvatarProperties Properties
+ {
+ get => avatarProperties;
+ set
+ {
+ avatarProperties = value;
+ }
+ }
+
+ /// <summary>
+ /// Create an initialized AvatarModel.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Avatar() : base()
+ {
+ InitAvatar();
+ }
+
+ /// <summary>
+ /// Create an initialized AREmojiDefaultAvatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Avatar(AvatarInfo avatarInfo) : base(avatarInfo.ResourcePath)
+ {
+ InitAvatar();
+ }
+
+ /// <summary>
+ /// Create an initialized Avatar.
+ /// </summary>
+ /// <param name="avatarUrl">avatar file url.(e.g. glTF).</param>
+ /// <param name="resourceDirectoryUrl"> The url to derectory containing resources: binary, image etc.</param>
+ /// <remarks>
+ /// If resourceDirectoryUrl is empty, the parent directory url of avatarUrl is used for resource url.
+ ///
+ /// http://tizen.org/privilege/mediastorage for local files in media storage.
+ /// http://tizen.org/privilege/externalstorage for local files in external storage.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Avatar(string avatarUrl, string resourceDirectoryUrl = "") : base(avatarUrl, resourceDirectoryUrl)
+ {
+ InitAvatar();
+ }
+
+ /// <summary>
+ /// Copy constructor.
+ /// </summary>
+ /// <param name="avatar">Source object to copy.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Avatar(Avatar avatar) : base(avatar)
+ {
+ InitAvatar();
+ }
+
+ #region Manage Animating
+
+ /// <summary>
+ /// Plays the specified avatar animation with an optional duration and loop count.
+ /// </summary>
+ /// <param name="animationInfo">The AnimationInfo object containing information about the desired avatar animation.</param>
+ /// <param name="duration">The duration of the animation in milliseconds (default is 3000).</param>
+ /// <param name="isLooping">A boolean indicating whether the animation should be looped or not.</param>
+ /// <param name="loopCount">The number of times to repeat the animation if it's set to loop.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PlayAnimation(AnimationInfo animationInfo, int duration = 3000, bool isLooping = false, int loopCount = 1)
+ {
+ if (animationInfo == null)
+ {
+ Tizen.Log.Error(LogTag, "animationInfo is null");
+ return;
+ }
+ if (animationInfo.MotionData == null)
+ {
+ Tizen.Log.Error(LogTag, "animationInfo.MotionData is null");
+ return;
+ }
+ motionAnimation = GenerateMotionDataAnimation(animationInfo.MotionData);
+ if (motionAnimation != null)
+ {
+ motionAnimation.Duration = duration;
+ motionAnimation.Looping = isLooping;
+ motionAnimation.LoopCount = loopCount;
+ motionAnimation.BlendPoint = 0.2f;
+ motionPlayer.PlayAnimation(motionAnimation);
+ }
+ else
+ {
+ Tizen.Log.Error(LogTag, "motionAnimation is null");
+ }
+ }
+
+ Animation motionAnimation;
+
+ /// <summary>
+ /// Plays the specified avatar animation with MotionData and an optional duration and loop count.
+ /// </summary>
+ /// <param name="motionData">The MotionData object containing information about the desired avatar animation.</param>
+ /// <param name="duration">The duration of the animation in milliseconds (default is 3000).</param>
+ /// <param name="isLooping">A boolean indicating whether the animation should be looped or not.</param>
+ /// <param name="loopCount">The number of times to repeat the animation if it's set to loop.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PlayAnimation(MotionData motionData, int duration = 3000, bool isLooping = false, int loopCount = 1)
+ {
+
+ if (motionData == null)
+ {
+ Tizen.Log.Error(LogTag, "motionData is null");
+ return;
+ }
+ var motionAnimation = GenerateMotionDataAnimation(motionData);
+ if (motionAnimation != null)
+ {
+ motionAnimation.Duration = duration;
+ motionAnimation.Looping = isLooping;
+ motionAnimation.LoopCount = loopCount;
+ motionAnimation.BlendPoint = 0.2f;
+ motionPlayer.PlayAnimation(motionAnimation);
+ }
+ else
+ {
+ Tizen.Log.Error(LogTag, "motionAnimation is null");
+ }
+ }
+
+ /// <summary>
+ /// Plays the specified avatar animation based on its index within the available animations and an optional duration and loop count.
+ /// </summary>
+ /// <param name="index">The zero-based index of the desired avatar animation within the list of available animations.</param>
+ /// <param name="duration">The duration of the animation in milliseconds (default is 3000).</param>
+ /// <param name="isLooping">A boolean indicating whether the animation should be looped or not.</param>
+ /// <param name="loopCount">The number of times to repeat the animation if it's set to loop.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PlayAnimation(int index, int duration = 3000, bool isLooping = false, int loopCount = 1)
+ {
+ //TODO by index
+ //var motionAnimation = GenerateMotionDataAnimation(animationInfoList[index].MotionData);
+ /*motionAnimation.Duration = duration;
+ motionAnimation.Looping = isLooping;
+ motionAnimation.LoopCount = loopCount;
+ motionAnimation.BlendPoint = 0.2f;
+
+ motionPlayer.PlayAnimation(motionAnimation);*/
+ }
+
+ /// <summary>
+ /// Pauses the currently playing avatar animation.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PauseMotionAnimation()
+ {
+ motionPlayer.PauseMotionAnimation();
+ }
+
+ /// <summary>
+ /// Stops the currently playing avatar animation.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void StopMotionAnimation()
+ {
+ motionPlayer?.StopMotionAnimation();
+ }
+
+ /// <summary>
+ /// Starts the eye blink animation for the current avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void StartEyeBlink()
+ {
+ motionPlayer?.StartEyeBlink();
+ }
+
+ /// <summary>
+ /// Pauses the eye blink animation for the current avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PauseEyeBlink()
+ {
+ motionPlayer?.PauseEyeBlink();
+ }
+
+ /// <summary>
+ /// Stops the eye blink animation for the current avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void StopEyeBlink()
+ {
+ motionPlayer?.StopEyeBlink();
+ }
+ #endregion
+
+ private void InitAvatar()
+ {
+ motionPlayer = new MotionPlayer();
+ var eyeMotionData = CreateEyeBlinkMotionData(200);
+ if (eyeMotionData == null)
+ {
+ Tizen.Log.Info(LogTag, "Failed Loading eyeAnimation");
+ }
+
+ ResourcesLoaded += (s, e) =>
+ {
+ var eyeAnimation = GenerateMotionDataAnimation(eyeMotionData);
+ if (eyeAnimation != null)
+ {
+ motionPlayer.SetBlinkAnimation(eyeAnimation);
+ }
+ };
+ }
+
+ private MotionData CreateEyeBlinkMotionData(int ms)
+ {
+ var keyFrames = new KeyFrames();
+ keyFrames.Add(0.1f, 0.0f);
+ keyFrames.Add(0.5f, 1.0f);
+ keyFrames.Add(0.9f, 0.0f);
+
+ var headBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
+ var headBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
+ var eyelashBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
+ var eyelashBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
+
+ var motionData = new MotionData(ms);
+ motionData.Add(headBlendShapeEyeLeft, new MotionValue(keyFrames));
+ motionData.Add(headBlendShapeEyeRight, new MotionValue(keyFrames));
+ motionData.Add(eyelashBlendShapeEyeLeft, new MotionValue(keyFrames));
+ motionData.Add(eyelashBlendShapeEyeRight, new MotionValue(keyFrames));
+
+ return motionData;
+ }
+ }
+}
--- /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.ComponentModel;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+ /// <summary>
+ /// The AvatarInfo class describes the properties of an Avatar object.
+ /// It includes information such as the name of the avatar, its thumbnail image, and associated resources.
+ /// This class helps users manage and organize their Avatar assets more effectively.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class AvatarInfo
+ {
+ /// <summary>
+ /// The Name property gets the name of the Avatar.
+ /// This value is read-only and cannot be modified directly.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string Name { get; private set; }
+
+ /// <summary>
+ /// The ThumbnailPath property gets the path to the thumbnail image representing the Avatar.
+ /// This value is read-only and cannot be modified directly.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string ThumbnailPath { get; private set; }
+
+ /// <summary>
+ /// The ResourcePath property gets the path to the resource files associated with the Avatar.
+ /// This value is intended for internal use only and should not be accessed by users directly.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal string ResourcePath { get; private set; }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal AvatarInfoOption avatarInfoOption { get; private set; }
+
+ /// <summary>
+ /// Initializes a new instance of the AvatarInfo class with the specified file path, name, and option.
+ /// If no option is provided, the default is AvatarInfoOption.Thumbnail.
+ /// </summary>
+ /// <param name="name">The name of the Avatar.</param>
+ /// <param name="path">The full path to the Avatar file.</param>
+ /// <param name="info">The option specifying what type of information should be loaded from the file (thumbnail or resource).</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AvatarInfo(string name, string path, AvatarInfoOption info = AvatarInfoOption.Thumbnail)
+ {
+ this.Name = name;
+ this.avatarInfoOption = info;
+
+ if (info == AvatarInfoOption.Thumbnail)
+ {
+ ThumbnailPath = path;
+ }
+ else
+ {
+ ResourcePath = path;
+ }
+ }
+
+ internal AvatarInfo(string directoryPath)
+ {
+ string path = ApplicationResourcePath + EmojiAvatarResourcePath;
+ Name = directoryPath.Substring(path.Length, directoryPath.Length - path.Length);
+ ResourcePath = $"{directoryPath}/{AIAvatar.ExternalModel}";
+ }
+ }
+
+ /// <summary>
+ /// The AvatarInfoOption enumeration defines the options that determine how AvatarInfo instances are displayed or managed.
+ /// Currently it has two values: Thumbnail and Resource.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum AvatarInfoOption
+ {
+
+ /// <summary>
+ /// Thumbnail indicates that the AvatarInfo instance should display or manipulate the thumbnail image of the Avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Thumbnail = 0,
+ /// <summary>
+ /// Resource indicates that the AvatarInfo instance should display or manipulate the resource files associated with the Avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Resource = 1,
+ }
+}
--- /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;
+using Tizen.NUI.Scene3D;
+
+namespace Tizen.AIAvatar
+{
+
+ /// <summary>
+ /// The Avatar class contains an inner AvatarProperties class.
+ /// This class manages AvatarProperty information using the AvatarPropertyMapper class.
+ /// By default, it includes jointMapper, blendShapeMapper, and nodeMapper, which automatically generate Properties based on model information.
+ /// This structure enables users to work with Avatar properties in a more convenient way.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class AvatarProperties
+ {
+ private AvatarPropertyMapper jointMapper;
+ private AvatarPropertyMapper blendShapeMapper;
+ private AvatarPropertyMapper nodeMapper;
+
+ internal event EventHandler<AvatarProperties> PropertiesChanged;
+
+ /// <summary>
+ /// The JointMapper property gets or sets the AvatarPropertyMapper responsible for mapping joint information in the Avatar model.
+ /// When setting this property, any changes made will trigger the AvatarPropertiesChanged event if it has been subscribed to.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AvatarPropertyMapper JointMapper
+ {
+ get
+ {
+ return jointMapper;
+ }
+ set
+ {
+ jointMapper = value;
+ PropertiesChanged?.Invoke(jointMapper, this);
+ }
+ }
+
+ /// <summary>
+ /// The BlendShapeMapper property gets or sets the AvatarPropertyMapper responsible for managing blend shape information in the Avatar model.
+ /// When setting this property, any changes made will trigger the AvatarPropertiesChanged event if it has been subscribed to.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AvatarPropertyMapper BlendShapeMapper
+ {
+ get
+ {
+ return blendShapeMapper;
+ }
+ set
+ {
+ blendShapeMapper = value;
+ PropertiesChanged?.Invoke(blendShapeMapper, this);
+ }
+ }
+
+ /// <summary>
+ /// The NodeMapper property gets or sets the AvatarPropertyMapper responsible for managing node information in the Avatar model.
+ /// When setting this property, any changes made will trigger the AvatarPropertiesChanged event if it has been subscribed to.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AvatarPropertyMapper NodeMapper
+ {
+ get
+ {
+ return nodeMapper;
+ }
+ set
+ {
+ nodeMapper = value;
+ PropertiesChanged?.Invoke(nodeMapper, this);
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the AvatarProperties class with the specified joint mapper, blend shape mapper, and node mapper.
+ /// These mappers are used to map between the Avatar's underlying model data and its corresponding properties.
+ /// </summary>
+ /// <param name="jointMapper">The AvatarPropertyMapper for joints.</param>
+ /// <param name="blendShapeMapper">The AvatarPropertyMapper for blend shapes.</param>
+ /// <param name="nodeMapper">The AvatarPropertyMapper for nodes.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AvatarProperties(AvatarPropertyMapper jointMapper, AvatarPropertyMapper blendShapeMapper, AvatarPropertyMapper nodeMapper)
+ {
+ JointMapper = new AvatarPropertyMapper(jointMapper);
+ BlendShapeMapper = new AvatarPropertyMapper(blendShapeMapper);
+ NodeMapper = new AvatarPropertyMapper(nodeMapper);
+ }
+
+ /// <summary>
+ /// This method generates a MotionIndex to be used in animations based on the NodeType and BlendShapeType using the model information of an Avatar.
+ /// </summary>
+ /// <param name="nodeType">Node type</param>
+ /// <param name="blendShapeType">Blend shape type</param>
+ /// <returns>The generated MotionIndex</returns>
+ public MotionIndex CreateBlendShapeMotionIndex(NodeType nodeType, BlendShapeType blendShapeType)
+ {
+ var motionIndex = new AvatarBlendShapeIndex(NodeMapper, nodeType, BlendShapeMapper, blendShapeType);
+ return motionIndex;
+ }
+ }
+}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
* limitations under the License.
*
*/
+
using System.Collections.Generic;
using System.ComponentModel;
namespace Tizen.AIAvatar
{
/// <summary>
- /// TODO : Explain more detail
+ /// The AvatarPropertyMapper class manages property mapping information for specific attributes of an Avatar model.
+ /// It primarily maps the names of AvatarProperty to their actual storage locations.
+ /// By doing so, developers can directly read or write the values of these properties using their respective names.
+ /// This approach provides consistency and convenience when working with Avatar models.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public class AvatarPropertyMapper
private uint customIndexCounter = 0;
/// <summary>
- /// Create an initialized AvatarPropertyNameMapper.
- /// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarPropertyMapper()
- {
- mapper = new Dictionary<uint, string>();
- customIndexCounter = 0u;
- }
-
- /// <summary>
- /// Copy constructor.
+ /// Get current mapper information.
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarPropertyMapper(AvatarPropertyMapper rhs)
+ public Dictionary<uint, string> Mapper
{
- if (rhs != null)
- {
- mapper = new Dictionary<uint, string>(rhs.Mapper);
- customIndexCounter = rhs.customIndexCounter;
- }
- else
+ get
{
- mapper = new Dictionary<uint, string>();
- customIndexCounter = 0u;
+ return mapper;
}
}
+ /// <summary>
+ /// Indexer method. Allows accessing and setting the property names using array notation.
+ /// </summary>
+ /// <param name="index">The index of property what we want to set</param>
+ /// <returns>The index of property, or uint.MaxValue if not exist</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
- protected uint CustomIndexCounter
+ public string this[uint index]
{
- get
+ set
{
- return customIndexCounter;
+ SetPropertyName(index, value);
}
- set
+ get
{
- customIndexCounter = value;
+ return GetPropertyName(index);
}
}
/// <summary>
- /// Get current mapper information.
+ /// Create an initialized AvatarPropertyNameMapper.
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
- public Dictionary<uint, string> Mapper
+ public AvatarPropertyMapper()
{
- get
- {
- return mapper;
- }
+ mapper = new Dictionary<uint, string>();
+ customIndexCounter = 0u;
}
- /// <summary>
- /// TODO : Explain me.
- /// </summary>
- /// <param name="index">The index of property what we want to set</param>
- /// <returns>The index of property, or uint.MaxValue if not exist</returns>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ /// <summary>
+ /// Copy constructor.
+ /// Creates a new instance of the AvatarPropertyMapper class by copying the contents of another existing AvatarPropertyMapper instance.
+ /// </summary>
+ /// <param name="source">The source AvatarPropertyMapper instance to be copied.</param>
[EditorBrowsable(EditorBrowsableState.Never)]
- public string this[uint index]
+ public AvatarPropertyMapper(AvatarPropertyMapper source)
{
- set
+ if (source != null)
{
- SetPropertyName(index, value);
+ mapper = new Dictionary<uint, string>(source.Mapper);
+ customIndexCounter = source.customIndexCounter;
}
- get
+ else
{
- return GetPropertyName(index);
+ mapper = new Dictionary<uint, string>();
+ customIndexCounter = 0u;
}
}
- /// <summary>
- /// TODO : Explain me.
- /// </summary>
- /// <param name="name">The name of custom property</param>
- /// <returns>The index of property matched with name.</returns>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ /// <summary>
+ /// Registers a custom property by name and returns its index.
+ /// </summary>
+ /// <param name="name">The name of custom property</param>
+ /// <returns>The index of property matched with name.</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public uint RegisterCustomProperty(string name)
{
return ret;
}
- /// <summary>
- /// TODO : Explain me.
- /// </summary>
- /// <param name="name">The name of property what we want to get index</param>
- /// <returns>The index of property, or uint.MaxValue if not exist</returns>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
+ /// <summary>
+ /// Returns the index of a property by its name.
+ /// </summary>
+ /// <param name="name">The name of property what we want to get index</param>
+ /// <returns>The index of property, or uint.MaxValue if not exist</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public uint GetPropertyIndexByName(string name)
{
return uint.MaxValue;
}
- /// <summary>
- /// TODO : Explain me.
- /// </summary>
- /// <param name="index">The index of property what we want to set</param>
- /// <param name="name">The name of property what we want to set</param>
- /// <remark>
- /// New property will be added if we use index that not exist in mapper.
- /// </remark>
- internal void SetPropertyName(uint index, string name)
+ /// <summary>
+ /// Sets the property name at the given index.
+ /// </summary>
+ /// <param name="index">The index of property what we want to set</param>
+ /// <param name="name">The name of property what we want to set</param>
+ /// <remark>
+ /// New property will be added if we use index that not exist in mapper.
+ /// </remark>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SetPropertyName(uint index, string name)
{
mapper.TryAdd(index, name);
}
- /// <summary>
- /// TODO : Explain me.
- /// </summary>
- /// <param name="index">The index of property what we want to set</param>
- /// <returns>The name of property, or null if not exist</returns>
- internal string GetPropertyName(uint index)
+ /// <summary>
+ /// Gets the property name at the given index.
+ /// </summary>
+ /// <param name="index">The index of property what we want to set</param>
+ /// <returns>The name of property, or null if not exist</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string GetPropertyName(uint index)
{
string ret = null;
mapper.TryGetValue(index, out ret);
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
{
/// <summary>
/// The type of predefined blendshape. We can customize each type name by "TODO_mapper"
- /// TODO : Explain me
- /// TODO : Need to check each joint exist in AR Emoji
- /// Note : This is temperal name of joints.
+ /// The basic names provided by AIAvatar to control the default avatar of AREmoji.
+ /// Contains the BlendShape information of AIAvatar.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- internal enum BlendShapeType
+ public enum BlendShapeType
{
#region Left Eyes
/// <summary>
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
namespace Tizen.AIAvatar
{
/// <summary>
- /// The type of predefined skeletal joint. We can customize each type name by "TODO_mapper"
- /// TODO : Explain me
- /// TODO : Need to check each joint exist in AR Emoji
- /// Note : This is temperal name of joints.
+ /// The type of predefined skeleton joint. We can customize each type name by "TODO_mapper"
+ /// The basic names provided by AIAvatar to control the default avatar of AREmoji.
+ /// Contains the joint information of AIAvatar.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- internal enum JointType
+ public enum JointType
{
#region Head
/// <summary>
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
* limitations under the License.
*
*/
+
using System.ComponentModel;
-using Tizen.Uix.Tts;
namespace Tizen.AIAvatar
{
+ /// <summary>
+ /// The type of predefined node. We can customize each type name by "TODO_mapper"
+ /// The basic names provided by AIAvatar to control the default avatar of AREmoji.
+ /// Contains the node information of AIAvatar.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public struct VoiceInfo
+ public enum NodeType
{
- private string lang;
- private Voice type;
-
/// <summary>
- ///
+ /// head geometry
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public string Lang { get => lang; set => lang = value; }
-
+ HeadGeo,
+ /// <summary>
+ /// mouth geometry
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ MouthGeo,
/// <summary>
- ///
+ /// eyelash geometry
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public Voice Type { get => type; set => type = value; }
+ EyelashGeo
}
}
using System.Net.Http;
using System;
using System.Threading.Tasks;
-using Tizen.Uix.Tts;
-using System.ComponentModel;
namespace Tizen.AIAvatar
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class AvatarLLM
+ internal class EmotionAnalyzer
{
- private AvatarTTS avatarTTS;
+ private LipSyncController avatarTTS;
private IRestClient restClient;
private const string playgroundURL = "https://playground-api.sec.samsung.net";
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal AvatarLLM()
+ internal EmotionAnalyzer()
{
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void InitAvatarLLM(AvatarTTS avatarTTS)
+ internal void InitAvatarLLM(LipSyncController avatarTTS)
{
this.avatarTTS = avatarTTS;
// Setup RestClinet
restClient = restClientFactory.CreateClient(playgroundURL);
}
- [EditorBrowsable(EditorBrowsableState.Never)]
internal async Task StartTTSWithLLMAsync(string text, string token)
{
var bearerToken = token;
//TTS 호출
var voiceInfo = new VoiceInfo()
{
- Lang = "en_US",
- Type = Voice.Female,
+ Language = "en_US",
+ Type = VoiceType.Female,
};
- avatarTTS.PlayTTSAsync(content, voiceInfo, (o, e) => {
-
+ avatarTTS.PlayTTSAsync(content, voiceInfo, (o, e) =>
+ {
+
});
}
--- /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.ComponentModel;
+
+namespace Tizen.AIAvatar
+{
+ /// <summary>
+ /// Manages facial expression control for avatars based on input text sentiment analysis results.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class EmotionController
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EmotionController"/> class without an avatar reference.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public EmotionController()
+ {
+
+ }
+
+ /// <summary>
+ /// Initializes the EmotionController by setting up the necessary components for managing facial expressions in the avatar.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Initialize()
+ {
+
+ }
+ /// <summary>
+ /// This method analyzes emotion the given text.
+ /// </summary>
+ /// <param name="text">The text to analyze</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void AnalizeEmotion(string text)
+ {
+
+ }
+
+ /// <summary>
+ /// This method starts playing the emotion facial.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PlayEmotionFacial()
+ {
+
+ }
+
+ /// <summary>
+ /// This method pauses the emotion facial.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PauseEmotionFacial()
+ {
+
+ }
+
+ /// <summary>
+ /// This method stops the emotion facial.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void StopEmotionFacial()
+ {
+
+ }
+ }
+}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
using System.Collections.Generic;
using System.IO;
+using System.ComponentModel;
using static Tizen.AIAvatar.AIAvatar;
namespace Tizen.AIAvatar
{
- internal static class AvatarExtension
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static class AvatarExtension
{
- internal static List<AvatarInfo> GetDefaultAvatarList()
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static List<AvatarInfo> GetDefaultAvatarList()
{
var list = new List<AvatarInfo>();
var avatarModelFolders = Directory.GetDirectories(ApplicationResourcePath + EmojiAvatarResourcePath);
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
*
*/
-using System;
-using System.Collections.Generic;
-using System.Text;
using Tizen.NUI.Scene3D;
+using System.ComponentModel;
namespace Tizen.AIAvatar
{
- internal static class SceneViewExtension
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static class SceneViewExtension
{
- internal static void SetAlphaMaskUrl(this SceneView sceneView, string url)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetAlphaMaskUrl(this SceneView sceneView, string url)
{
var setValue = new Tizen.NUI.PropertyValue(url);
sceneView.SetProperty(Interop.AlphaMaskURLGet(), setValue);
setValue.Dispose();
}
- internal static string GetAlphaMaskUrl(this SceneView sceneView)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static string GetAlphaMaskUrl(this SceneView sceneView)
{
var returnValue = "";
var invertYAxis = sceneView.GetProperty(Interop.AlphaMaskURLGet());
return returnValue;
}
- internal static void SetMaskContentScaleFactor(this SceneView sceneView, float factor)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void SetMaskContentScaleFactor(this SceneView sceneView, float factor)
{
var setValue = new Tizen.NUI.PropertyValue(factor);
sceneView.SetProperty(Interop.MaskContentScaleGet(), setValue);
setValue.Dispose();
}
- internal static float GetMaskContentScaleFactor(this SceneView sceneView)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static float GetMaskContentScaleFactor(this SceneView sceneView)
{
var returnValue = 0.0f;
var invertYAxis = sceneView.GetProperty(Interop.MaskContentScaleGet());
return returnValue;
}
- internal static void EnableCropToMask(this SceneView sceneView, bool enableCropToMask)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static void EnableCropToMask(this SceneView sceneView, bool enableCropToMask)
{
var setValue = new Tizen.NUI.PropertyValue(enableCropToMask);
sceneView.SetProperty(Interop.CropToMaskGet(), setValue);
setValue.Dispose();
}
- internal static bool IsEnabledCropToMask(this SceneView sceneView)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool IsEnabledCropToMask(this SceneView sceneView)
{
bool returnValue = false;
var invertYAxis = sceneView.GetProperty(Interop.CropToMaskGet());
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/// </code>
/// </example>
[EditorBrowsable(EditorBrowsableState.Never)]
- public class AvatarBlendShapeIndex : BlendShapeIndex
+ internal class AvatarBlendShapeIndex : BlendShapeIndex
{
internal AvatarPropertyMapper nameMapper = null;
internal uint blendShapeType;
- /// <summary>
- /// Create an initialized avatar blend shape index.
- /// </summary>
- /// <param name="mapper">Name mapper for this index</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarBlendShapeIndex(AvatarPropertyMapper mapper) : base()
+ internal AvatarBlendShapeIndex(AvatarPropertyMapper mapper) : base()
{
nameMapper = mapper;
}
- /// <summary>
- /// Create an initialized avatar blend shape index with input blend shape ID.
- /// </summary>
- /// <param name="mapper">Name mapper for this index</param>
- /// <param name="blendShapeId">Blend shape ID for this motion index</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarBlendShapeIndex(AvatarPropertyMapper mapper, PropertyKey blendShapeId) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeId)))
+ internal AvatarBlendShapeIndex(AvatarPropertyMapper mapper, PropertyKey blendShapeId) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeId)))
{
nameMapper = mapper;
}
- /// <summary>
- /// Create an initialized avatar blend shape index with blend shape type.
- /// </summary>
- /// <param name="mapper">Name mapper for this index</param>
- /// <param name="blendShapeType">Type of blend shape for this motion index</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
+ internal AvatarBlendShapeIndex(AvatarPropertyMapper nodeMapper, NodeType nodeType, PropertyKey blendShapeId)
+ : base(new PropertyKey(GetPropertyNameFromMapper(nodeMapper, (uint)nodeType)), blendShapeId)
+ {
+ }
+
internal AvatarBlendShapeIndex(AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType) : this(blendShapeMapper, (uint)blendShapeType)
{
}
- /// <summary>
- ///
- /// </summary>
- /// <param name="mapper">Name mapper for this index</param>
- /// <param name="blendShapeType">Type of blend shape for this motion index</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarBlendShapeIndex(AvatarPropertyMapper mapper, uint blendShapeType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeType)))
+ internal AvatarBlendShapeIndex(AvatarPropertyMapper mapper, uint blendShapeType) : base(new PropertyKey(GetPropertyNameFromMapper(mapper, blendShapeType)))
{
nameMapper = mapper;
this.blendShapeType = blendShapeType;
}
- /// <summary>
- ///
- /// </summary>
- /// <param name="mapper">Name mapper for this index</param>
- /// <param name="blendShapeType">Type of blend shape for this motion index</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal AvatarBlendShapeIndex(AvatarPropertyMapper nodeMapper, NodeType nodeType, AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType) : base(new PropertyKey(GetPropertyNameFromMapper(nodeMapper, (uint)nodeType)), new PropertyKey(GetPropertyNameFromMapper(blendShapeMapper, (uint)blendShapeType)))
+ internal AvatarBlendShapeIndex(AvatarPropertyMapper nodeMapper, NodeType nodeType, AvatarPropertyMapper blendShapeMapper, BlendShapeType blendShapeType)
+ : base(new PropertyKey(GetPropertyNameFromMapper(nodeMapper, (uint)nodeType)), new PropertyKey(GetPropertyNameFromMapper(blendShapeMapper, (uint)blendShapeType)))
{
nameMapper = blendShapeMapper;
this.blendShapeType = (uint)blendShapeType;
{
return id.StringKey;
}
- return mapper?.GetPropertyName((uint)id.IndexKey) ?? "";
+
+ var str = mapper?.GetPropertyName((uint)id.IndexKey) ?? "";
+ return str;
}
/// <summary>
- /// Get the name of given JointType.
+ /// Get the name of given BlendShape.
/// </summary>
/// <param name="mapper">Name mapper for given index</param>
- /// <param name="blendShapeType">Type of joint what we want to get name</param>
+ /// <param name="type">Type of joint what we want to get name</param>
/// <returns>Name, or null if invalid</returns>
- private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, uint blendShapeType)
+ private static string GetPropertyNameFromMapper(AvatarPropertyMapper mapper, uint type)
{
- return mapper?.GetPropertyName(blendShapeType) ?? "";
+ var str = mapper?.GetPropertyName(type) ?? "";
+ return str;
}
/// <summary>
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/// </code>
/// </example>
[EditorBrowsable(EditorBrowsableState.Never)]
- public class AvatarJointTransformIndex : MotionTransformIndex
+ internal class AvatarJointTransformIndex : MotionTransformIndex
{
internal AvatarPropertyMapper nameMapper = null;
internal uint jointType;
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
*
*/
-using System;
using System.Collections.Generic;
-using System.Text;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
namespace Tizen.AIAvatar
{
private static AvatarPropertyMapper defaultBlendShapeNameMapper = new AvatarPropertyMapper();
private static AvatarPropertyMapper defaultNodeMapper = new AvatarPropertyMapper();
-
internal DefaultAvatarProperties() : base(defaultJointMapper, defaultBlendShapeNameMapper, defaultNodeMapper)
{
+ Initialize();
+ }
+
+ private void Initialize()
+ {
foreach (var indexNamePair in blendShapeList)
{
- defaultBlendShapeNameMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
+ BlendShapeMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
}
foreach (var indexNamePair in jointList)
{
- defaultJointMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
+ JointMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
}
foreach (var indexNamePair in nodeList)
{
- defaultNodeMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
+ NodeMapper.SetPropertyName((uint)indexNamePair.Item1, indexNamePair.Item2);
}
+
}
#region AR Emoji BlendShape name list
(NodeType.EyelashGeo, "eyelash_GEO"),
};
#endregion
-
}
}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
internal class SystemUtils
{
- internal static void ST()
- {
- Tizen.Log.Error("MYLOG", System.Environment.StackTrace);
- }
-
internal static string GetFileName(string path)
{
return System.IO.Path.GetFileName(path);
namespace Tizen.AIAvatar
{
[EditorBrowsable(EditorBrowsableState.Never)]
- internal class AsyncLipSyncer : LipSyncer
+ internal class AsyncLipSyncer
{
private readonly uint AsyncPlayTime = 160;
private Queue<Animation> lipAnimations;
{
if (!isAsyncInit)
{
- CurrentMotionState = AvatarMotionState.Stopped;
+ //TODO : State is Stop
}
else
{
{
Tizen.Log.Error(LogTag, "Finish vowel lip sync");
- AudioPlayer.Stop();
- CurrentMotionState = AvatarMotionState.Stopped;
+
+ //Audio Player is Stop, AudioPlayer.Stop();
+ //TODO : State is Stop
DestroyVowelTimer();
isAsyncInit = false;
}
}
}
+ private void EnqueueVowels(byte[] buffer, bool deleteLast = false)
+ {
+ /*
+ var vowels = PredictVowels(buffer);
+ if (vowels != null)
+ {
+ vowelPools.Enqueue(vowels);
+ if (deleteLast)
+ {
+ var vowelList = new List<string>(vowels);
+ vowelList.RemoveAt(vowelList.Count - 1);
+ vowels = vowelList.ToArray();
+ }
+ }*/
+ }
+
+ internal Animation CreateAsyncLipAnimation(byte[] buffer, int sampleRate)
+ {
+ EnqueueVowels(buffer, false);
+ return null;
+ //return CreateLipAnimationByVowelsQueue(sampleRate);
+ }
+
internal void EnqueueAnimation(byte[] recordBuffer, int sampleRate, int audioLength)
{
var createdAni = CreateAsyncLipAnimation(recordBuffer, sampleRate);
var lipAnimation = lipAnimations.Dequeue();
lipAnimation.Finished += OnLipAnimationFinished;
- ResetLipAnimation(lipAnimation);
- PlayLipAnimation();
+ //ResetLipAnimation(lipAnimation);
+ //PlayLipAnimation();
var audioBuffer = lipAudios.Dequeue();
- AudioPlayer.PlayAsync(audioBuffer, sampleRate);
+
+ //Audio Playe rAsync Play
+ //AudioPlayer.PlayAsync(audioBuffer, sampleRate);
return true;
}
--- /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.Collections.Generic;
+using System.ComponentModel;
+using System;
+using Tizen.Uix.Tts;
+
+using static Tizen.AIAvatar.AIAvatar;
+using Tizen.Multimedia;
+using Tizen.NUI.Scene3D;
+using Tizen.NUI;
+
+namespace Tizen.AIAvatar
+{
+ /// <summary>
+ /// A controller class used to manage lip sync functionality for avatars.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class LipSyncController : IDisposable
+ {
+ private TTSController ttsController;
+ private AudioRecorder audioRecorder;
+ private LipSyncer lipSyncer;
+
+ private Avatar avatar;
+
+ private event EventHandler ttsReadyFinished;
+ private readonly Object ttsReadyFinishedLock = new Object();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LipSyncController"/> class.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public LipSyncController(Avatar avatar)
+ {
+ this.avatar = avatar;
+
+ audioRecorder = new AudioRecorder();
+ lipSyncer = new LipSyncer();
+
+ lipSyncer.CreatedKeyFrameAnimation += OnCreatedKeyFrameAnimation;
+ }
+
+ private Animation CreateLipAnimation(AnimationKeyFrame animationKeyFrames, bool isMic = false)
+ {
+ var animationTime = (int)(animationKeyFrames.AnimationTime * 1000f);
+ var lipAnimation = new Animation(animationTime);
+
+ var motionData = new MotionData(animationTime);
+ for (var i = 0; i < animationKeyFrames.NodeNames.Length; i++)
+ {
+ var nodeName = animationKeyFrames.NodeNames[i];
+ for (var j = 0; j < animationKeyFrames.BlendShapeCounts[i]; j++)
+ {
+ var blendShapeIndex = new BlendShapeIndex(new PropertyKey(nodeName), new PropertyKey(j));
+ var keyFrameList = animationKeyFrames.GetKeyFrames(nodeName, j);
+ if (keyFrameList.Count == 0)
+ {
+ continue;
+ }
+
+ var keyFrames = new KeyFrames();
+ CreateKeyTimeFrames(ref keyFrames, keyFrameList, isMic);
+
+ motionData.Add(blendShapeIndex, new MotionValue(keyFrames));
+ lipAnimation = avatar.GenerateMotionDataAnimation(motionData);
+ }
+ }
+ return lipAnimation;
+ }
+
+ private KeyFrames CreateKeyTimeFrames(ref KeyFrames keyFrames, List<KeyFrame> keyFrameList, bool isMic = false)
+ {
+ foreach (var key in keyFrameList)
+ {
+ keyFrames.Add(key.time, key.value);
+ }
+ if (!isMic) keyFrames.Add(1.0f, 0.0f);
+
+ return keyFrames;
+ }
+
+ private Animation OnCreatedKeyFrameAnimation(AnimationKeyFrame animationKeyFrame, bool isMic)
+ {
+ if (animationKeyFrame == null)
+ {
+ Tizen.Log.Error(LogTag, "animtionKeyFrame is null");
+ }
+ var lipAnimation = CreateLipAnimation(animationKeyFrame, isMic);
+ return lipAnimation;
+ }
+
+ /// <summary>
+ /// Occurs when text-to-speech synthesis has finished and the audio data is ready to play.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public event EventHandler TTSReadyFinished
+ {
+ add
+ {
+ lock (ttsReadyFinishedLock)
+ {
+ ttsReadyFinished += value;
+ }
+
+ }
+
+ remove
+ {
+ lock (ttsReadyFinishedLock)
+ {
+ if (ttsReadyFinished == null)
+ {
+ Log.Error(LogTag, "ttsReadyFinished is null");
+ return;
+ }
+ ttsReadyFinished -= value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the current Text-To-Speech client associated with the Lip Sync Controller.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public TtsClient CurrentTTSClient => ttsController?.TtsHandle;
+
+ /// <summary>
+ /// Initializes the Text-To-Speech system for use with the Lip Sync Controller.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void InitializeTTS()
+ {
+ if (ttsController == null)
+ {
+ try
+ {
+ ttsController = new TTSController();
+ //TODO : LipSync Event Connect
+ ttsController.PreparedSyncText += OnPreparedSyncText;
+ ttsController.StoppedTTS += OnStoppedTTS;
+ ttsController.UpdatedBuffer += OnUpdatedBuffer;
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ }
+ }
+ }
+
+ private void OnUpdatedBuffer(object sender, TTSControllerEventArgs e)
+ {
+ throw new NotImplementedException();
+ if (lipSyncer != null)
+ {
+ Log.Error(LogTag, "OnTTSBufferChanged");
+ /*
+ lipSyncer.EnqueueAnimation(recordBuffer, sampleRate, audioLength);
+ if (!isAsyncLipStarting)
+ {
+ lipSyncer.StartAsyncLipPlayTimer();
+ isAsyncLipStarting = true;
+ }*/
+ }
+ else
+ {
+ Log.Error(LogTag, "avatarLipSyncer is null");
+ }
+ }
+
+ private void OnStoppedTTS(object sender, TTSControllerEventArgs e)
+ {
+ lipSyncer.Stop();
+ }
+
+ private void OnPreparedSyncText(object sender, TTSControllerEventArgs e)
+ {
+ var data = e.AudioData;
+ var sampleRate = e.SampleRate;
+
+ // Play Lipsync Animation by Audio
+ lipSyncer.PlayAudio(data, sampleRate);
+ }
+
+ /// <summary>
+ /// Deinitializes the Text-To-Speech system for use with the Lip Sync Controller.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void DeInitializeTTS()
+ {
+ if (ttsController != null)
+ {
+ try
+ {
+ ttsController.DeinitTts();
+ ttsController = null;
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Returns a list of supported voices for the Text-To-Speech system.
+ /// </summary>
+ /// <returns></returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public List<VoiceInfo> GetSupportedVoices()
+ {
+ return ttsController.GetSupportedVoices();
+ }
+
+ /// <summary>
+ /// Plays the given audio with LipSync and returns whether it was successful or not.
+ /// If the lip syncer is null, logs an error and returns false.
+ /// The lipSyncer plays the audio using the provided byte array and sample rate.
+ /// </summary>
+ /// <param name="audio">The audio data to be played in a byte array format.</param>
+ /// <param name="sampleRate">The sampling rate of the audio data, default value is 24000 Hz.</param>
+ public bool PlayLipSync(byte[] audio, int sampleRate = 24000)
+ {
+ if (lipSyncer == null)
+ {
+ Log.Error(LogTag, "lipSyncer is null");
+ return false;
+ }
+ lipSyncer.PlayAudio(audio, sampleRate);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Plays the given audio with LipSync and returns whether it was successful or not.
+ /// If the lip syncer is null, logs an error and returns false.
+ /// The lipSyncer plays the audio using the provided byte array and sample rate.
+ /// </summary>
+ /// <param name="audio">The audio data to be played in a byte array format.</param>
+ /// <param name="sampleRate">The sampling rate of the audio data, default value is 16000 Hz.</param>
+ public bool PlayLipSync(string path, int sampleRate = 24000)
+ {
+ var audio = Utils.ReadAllBytes(path);
+ if (audio == null)
+ {
+ Log.Error(LogTag, "audio data is null");
+ return false;
+ }
+ lipSyncer.PlayAudio(audio, sampleRate);
+
+ return true;
+ }
+
+ /// <summary>
+ /// Prepares the Text-To-Speech engine to synthesize speech from the provided text and voice info.
+ /// </summary>
+ /// <param name="text">The text to convert into speech.</param>
+ /// <param name="voiceInfo">The voice info to use for converting the text into speech.</param>
+ /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>
+ /// <returns><c>True</c> if preparation was successful, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PrepareTTS(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+
+ if (!ttsController.IsSupportedVoice(voiceInfo))
+ {
+ Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is not supported");
+ return false;
+ }
+
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+ {
+ Log.Info(LogTag, "TTS is not ready");
+ return false;
+ }
+
+ try
+ {
+ ttsController.AddText(text, voiceInfo);
+ ttsController.Prepare(ttsReadyFinishedCallback);
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Prepares the Text-To-Speech engine to synthesize speech from the provided text and language code.
+ /// </summary>
+ /// <param name="text">The text to convert into speech.</param>
+ /// <param name="lang">The two-letter ISO 639-1 language code to use for converting the text into speech (default is Korean - ko_KR).</param>
+ /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>
+ /// <returns><c>True</c> if preparation was successful, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PrepareTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+ if (!ttsController.IsSupportedVoice(lang))
+ {
+ Log.Error(LogTag, $"{lang} is not supported");
+ return false;
+ }
+
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+ {
+ Log.Error(LogTag, "TTS is not ready");
+ return false;
+ }
+ try
+ {
+ ttsController.AddText(text, lang);
+ ttsController.Prepare(ttsReadyFinishedCallback);
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Plays the previously prepared Text-To-Speech audio data.
+ /// </summary>
+ /// <returns><c>True</c> if playback started successfully, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PlayPreparedTTS()
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+ return ttsController.PlayPreparedText();
+ }
+
+ /// <summary>
+ /// Converts the given text into speech using the specified voice info and plays the resulting audio immediately.
+ /// </summary>
+ /// <param name="text">The text to convert into speech.</param>
+ /// <param name="voiceInfo">The voice info to use for converting the text into speech.</param>
+ /// <returns><c>True</c> if playback started successfully, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PlayTTS(string text, VoiceInfo voiceInfo)
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+ if (!ttsController.IsSupportedVoice(voiceInfo))
+ {
+ Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is not supported");
+ return false;
+ }
+
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+ {
+ Log.Info(LogTag, "TTS is not ready");
+ return false;
+ }
+
+ try
+ {
+ ttsController.AddText(text, voiceInfo);
+ ttsController.Play();
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Converts the given text into speech using the specified language code and plays the resulting audio immediately.
+ /// </summary>
+ /// <param name="text">The text to convert into speech.</param>
+ /// <param name="lang">The two-letter ISO 639-1 language code to use for converting the text into speech (default is Korean - ko_KR).</param>
+ /// <returns><c>True</c> if playback started successfully, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PlayTTS(string text, string lang = "ko_KR")
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+ if (!ttsController.IsSupportedVoice(lang))
+ {
+ Log.Error(LogTag, $"{lang} is not supported");
+ return false;
+ }
+
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+ {
+ Log.Error(LogTag, "TTS is not ready");
+ return false;
+ }
+ try
+ {
+ ttsController.AddText(text, lang);
+ ttsController.Play();
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Asynchronously converts the given text into speech using the specified voice info and plays the resulting audio once it's ready.
+ /// </summary>
+ /// <param name="text">The text to convert into speech.</param>
+ /// <param name="voiceInfo">The voice info to use for converting the text into speech.</param>
+ /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>
+ /// <returns><c>True</c> if asynchronous conversion was initiated successfully, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PlayTTSAsync(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+ if (!ttsController.IsSupportedVoice(voiceInfo))
+ {
+ Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is not supported");
+ return false;
+ }
+
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+ {
+ Log.Info(LogTag, "TTS is not ready");
+ return false;
+ }
+
+ try
+ {
+ ttsController.AddText(text, voiceInfo);
+ ttsController.PlayAsync(ttsReadyFinishedCallback);
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Asynchronously converts the given text into speech using the specified language code and plays the resulting audio once it's ready.
+ /// </summary>
+ /// <param name="text">The text to convert into speech.</param>
+ /// <param name="lang">The two-letter ISO 639-1 language code to use for converting the text into speech (default is Korean - ko_KR).</param>
+ /// <param name="ttsReadyFinishedCallback">An optional callback that will be invoked when the TTS process is complete.</param>
+ /// <returns><c>True</c> if asynchronous conversion was initiated successfully, otherwise <c>False</c>.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PlayTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return false;
+ }
+
+ if (!ttsController.IsSupportedVoice(lang))
+ {
+ Log.Error(LogTag, $"{lang} is not supported");
+ return false;
+ }
+
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ if (ttsController.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
+ {
+ Log.Error(LogTag, "TTS is not ready");
+ return false;
+ }
+ try
+ {
+ ttsController.AddText(text, lang);
+ ttsController.PlayAsync(ttsReadyFinishedCallback);
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Pauses the currently playing Text-To-Speech audio.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void PauseTTS()
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return;
+ }
+
+ try
+ {
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ ttsController?.Pause();
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ }
+ }
+
+ /// <summary>
+ /// Stops the currently playing Text-To-Speech audio.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void StopTTS()
+ {
+ if (ttsController == null || ttsController.TtsHandle == null)
+ {
+ Log.Error(LogTag, "tts is null");
+ return;
+ }
+
+ try
+ {
+ Log.Info(LogTag, "Current TTS State :" + ttsController.TtsHandle.CurrentState);
+ ttsController?.Stop();
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, $"error :{e.Message}");
+ Log.Error(LogTag, $"{e.StackTrace}");
+ }
+ }
+
+ public void InitializeMic()
+ {
+ if (audioRecorder == null)
+ {
+ Tizen.Log.Error(LogTag, "audio record is null");
+ return;
+ }
+ audioRecorder.InitializeMic(lipSyncer, 160);
+ }
+
+ public void DeinitializeMic()
+ {
+ if (audioRecorder == null)
+ {
+ Tizen.Log.Error(LogTag, "audio record is null");
+ return;
+ }
+ audioRecorder.StartRecording();
+ }
+
+ public void StartMic()
+ {
+ if (audioRecorder == null)
+ {
+ Tizen.Log.Error(LogTag, "audio record is null");
+ return;
+ }
+ audioRecorder.StartRecording();
+ }
+
+ public void StopMic()
+ {
+ if (audioRecorder == null)
+ {
+ Tizen.Log.Error(LogTag, "audio record is null");
+ return;
+ }
+ audioRecorder.StopRecording();
+ }
+
+ public void PauseMic()
+ {
+ if (audioRecorder == null)
+ {
+ Tizen.Log.Error(LogTag, "audio record is null");
+ return;
+ }
+ audioRecorder.PauseRecording();
+ }
+
+ public void ResumeMic()
+ {
+ if(audioRecorder == null)
+ {
+ Tizen.Log.Error(LogTag, "audio record is null");
+ return;
+ }
+ audioRecorder.ResumeRecording();
+ }
+
+ /// <summary>
+ /// Releases unmanaged resources used by this instance.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Dispose()
+ {
+ if (ttsController != null)
+ {
+ ttsController.Dispose();
+ ttsController = null;
+ }
+
+ if (audioRecorder != null)
+ {
+ audioRecorder.Dispose();
+ audioRecorder = null;
+ }
+ }
+ }
+}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using Tizen.NUI;
using Tizen.NUI.Scene3D;
-
using static Tizen.AIAvatar.AIAvatar;
namespace Tizen.AIAvatar
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class LipSyncer : AnimationModule
+ internal class LipSyncer
{
- private Avatar avatar;
private Animation lipAnimation = null;
- //private VowelConverter vowelConverter;
+ private VowelConverter vowelConverter;
private AudioPlayer audioPlayer;
+ private event Func<AnimationKeyFrame, bool, Animation> TheEvent;
+
+ internal Func<AnimationKeyFrame, bool, Animation> CreatedKeyFrameAnimation;
//Mic
private Queue<string[]> vowelPools = new Queue<string[]>();
private string prevVowel = "sil";
- [EditorBrowsable(EditorBrowsableState.Never)]
internal LipSyncer()
{
+ vowelConverter = new VowelConverter();
+ audioPlayer = new AudioPlayer();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
internal AudioPlayer AudioPlayer { get { return audioPlayer; } }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Init(Animation lipAnimation)
+ public void SetLipAnimation(Animation lipAnimation)
{
this.lipAnimation = lipAnimation;
- //vowelConverter = new VowelConverter();
- audioPlayer = new AudioPlayer();
-
- CurrentMotionState = AvatarMotionState.Ready;
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Play(IAnimationModuleData data)
+ public void PlayAudio(byte[] audio, int sampleRate)
{
- if (data is LipSyncData lipSyncData)
+ if (audio != null)
{
- if (lipSyncData.AudioFile != null)
- {
- PlayLipSync(lipSyncData.AudioFile, lipSyncData.SampleRate);
- }
+ PlayLipSync(audio, sampleRate);
}
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Stop()
+ public void Stop()
{
StopLipSync();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Pause()
+ public void Pause()
{
PauseLipSync();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- public override void Destroy()
+ public void Destroy()
{
DestroyLipAnimation();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
- protected Animation CreateAsyncLipAnimation(byte[] buffer, int sampleRate)
- {
- EnqueueVowels(buffer, false);
- return CreateLipAnimationByVowelsQueue(sampleRate);
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
//TODO : lipAnimation 자체를 Animator안에서 생성하고 관리될 수 있게 수정.
protected void ResetLipAnimation(Animation lipAnimation)
{
}
}
- [EditorBrowsable(EditorBrowsableState.Never)]
protected void PlayLipAnimation()
{
if (lipAnimation == null)
lipAnimation?.Play();
}
- [EditorBrowsable(EditorBrowsableState.Never)]
protected void OnLipAnimationFinished(object sender, EventArgs e)
{
- CurrentMotionState = AvatarMotionState.Stopped;
}
private void PlayLipSync(byte[] audio)
Tizen.Log.Error(LogTag, "audi data is null");
return;
}
-
DestroyLipAnimation();
- var lipAnimation = CreateLipAnimation(audio, CurrentAudioOptions.SampleRate);
- if (lipAnimation != null)
+
+ var lipKeyframes = CreateKeyFrame(audio, CurrentAudioOptions.SampleRate);
+ if (lipKeyframes != null)
{
- ResetLipAnimation(lipAnimation);
- PlayLipAnimation();
+ var lipAnimation = CreatedKeyFrameAnimation?.Invoke(lipKeyframes, false);
+
+ if (lipAnimation != null)
+ {
+ ResetLipAnimation(lipAnimation);
+ PlayLipAnimation();
+ audioPlayer.Play(audio);
+ }
+ else
+ {
+ Tizen.Log.Error(LogTag, "lipAnimation is null");
+ }
}
else
{
-
- Tizen.Log.Error(LogTag, "lipAnimation is null");
+ Tizen.Log.Error(LogTag, "lipKeyframes is null");
}
- audioPlayer.Play(audio);
- CurrentMotionState = AvatarMotionState.Playing;
}
private void PlayLipSync(byte[] audio, int sampleRate)
{
DestroyLipAnimation();
- var lipAnimation = CreateLipAnimation(audio, sampleRate);
+ var lipKeyFrames = CreateKeyFrame(audio, sampleRate);
+ var lipAnimation = CreatedKeyFrameAnimation?.Invoke(lipKeyFrames, false);
if (lipAnimation != null)
{
ResetLipAnimation(lipAnimation);
PlayLipAnimation();
}
audioPlayer.Play(audio, sampleRate);
- CurrentMotionState = AvatarMotionState.Playing;
}
private void PlayLipSync(string path)
{
PauseLipAnimation();
audioPlayer.Pause();
- CurrentMotionState = AvatarMotionState.Paused;
}
private void StopLipSync()
{
- StopLipAnimation();
- audioPlayer.Stop();
- CurrentMotionState = AvatarMotionState.Stopped;
- }
-
- private void PauseLipAnimation()
- {
- if (lipAnimation != null)
- {
- lipAnimation?.Pause();
- }
- else
- {
- Log.Error(LogTag, "Current Lip Animation is null");
- }
- }
-
- private void StopLipAnimation()
- {
if (lipAnimation != null)
{
DestroyLipAnimation();
{
Log.Error(LogTag, "Current Lip Animation is null");
}
+ audioPlayer.Stop();
}
- private void DestroyLipAnimation()
+ private void PauseLipAnimation()
{
if (lipAnimation != null)
{
- lipAnimation.Stop();
- lipAnimation.Dispose();
- lipAnimation = null;
+ lipAnimation?.Pause();
+ }
+ else
+ {
+ Log.Error(LogTag, "Current Lip Animation is null");
}
}
- private Animation CreateLipAnimation(byte[] array, int sampleRate)
+ private void DestroyLipAnimation()
{
- Animation lipKeyframes = null;// CreateKeyFrame(array, sampleRate);
- if (lipKeyframes != null)
+ if (lipAnimation != null)
{
-
- return null;// CreateLipAnimation(lipKeyframes);
+ lipAnimation.Stop();
+ lipAnimation.Dispose();
+ lipAnimation = null;
}
- return null;
}
private void EnqueueVowels(byte[] buffer, bool deleteLast = false)
AttachPreviousVowel(vowelPools.Dequeue(), out var newVowels);
Log.Info(LogTag, $"vowelRecognition: {String.Join(", ", newVowels)}");
- //var lipKeyFrames = vowelConverter?.CreateKeyFrames(newVowels, sampleRate, true);
- return null;// CreateLipAnimation(lipKeyFrames, true);
+ var lipKeyFrames = vowelConverter?.CreateKeyFrames(newVowels, sampleRate, true);
+ var lipAnimation = CreatedKeyFrameAnimation?.Invoke(lipKeyFrames, true);
+
+ return lipAnimation;
}
return null;
}
private string[] PredictVowels(byte[] audioData)
{
- string[] vowels = null;// vowelConverter?.PredictVowels(audioData);
+ string[] vowels = vowelConverter?.PredictVowels(audioData);
return vowels;
}
prevVowel = vowels[vowels.Length - 1];
}
- /*
private AnimationKeyFrame CreateKeyFrame(byte[] audio, int sampleRate)
{
var keyFrames = vowelConverter?.CreateKeyFrames(audio, sampleRate);
return keyFrames;
}
- private Animation CreateLipAnimation(AnimationKeyFrame animationKeyFrames, bool isMic = false)
- {
- var animationTime = (int)(animationKeyFrames.AnimationTime * 1000f);
- var lipAnimation = new Animation(animationTime);
-
- var motionData = new MotionData(animationTime);
- for (var i = 0; i < animationKeyFrames.NodeNames.Length; i++)
- {
- var nodeName = animationKeyFrames.NodeNames[i];
- for (var j = 0; j < animationKeyFrames.BlendShapeCounts[i]; j++)
- {
- var blendShapeIndex = new BlendShapeIndex(new PropertyKey(nodeName), new PropertyKey(j));
- var keyFrameList = animationKeyFrames.GetKeyFrames(nodeName, j);
- if (keyFrameList.Count == 0)
- {
- continue;
- }
-
- var keyFrames = new KeyFrames();
- CreateKeyTimeFrames(ref keyFrames, keyFrameList, isMic);
-
- motionData.Add(blendShapeIndex, new MotionValue(keyFrames));
- lipAnimation = avatar.GenerateMotionDataAnimation(motionData);
- }
- }
- return lipAnimation;
- }
- private KeyFrames CreateKeyTimeFrames(ref KeyFrames keyFrames, List<KeyFrame> keyFrameList, bool isMic = false)
- {
- foreach (var key in keyFrameList)
- {
- keyFrames.Add(key.time, key.value);
- }
- if (!isMic) keyFrames.Add(1.0f, 0.0f);
-
- return keyFrames;
- }
- */
internal void OnRecordBufferChanged(byte[] recordBuffer, int sampleRate)
{
--- /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.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+ internal class CustomMfccExtractor : IMfccExtractor
+ {
+ private readonly int FilterBankSize = 24;
+
+ private int featureCount = 12;
+
+ private int blockSize;
+ private int frameSize;
+ private int hopSize;
+
+ private Window window;
+ private FFT fft;
+ private FilterBank filterBank;
+ private DCT dct;
+
+ private float[] block;
+ private float[] spectrum;
+ private float[] melSpectrum;
+
+ public CustomMfccExtractor(int samplingRate, float frameDuration, float hopDuration, int featureCount)
+ {
+ this.featureCount = featureCount;
+
+ frameSize = (int)Math.Round(samplingRate * frameDuration, 1);
+ hopSize = (int)Math.Round(samplingRate * hopDuration, 1);
+ blockSize = (int)Math.Pow(2, Math.Ceiling(Math.Log(frameSize, 2)));
+
+ window = new Window(frameSize);
+ fft = new FFT(blockSize);
+ filterBank = new FilterBank(FilterBankSize, samplingRate, blockSize);
+ dct = new DCT(FilterBankSize, this.featureCount);
+
+ block = new float[blockSize];
+ spectrum = new float[blockSize / 2 + 1];
+ melSpectrum = new float[FilterBankSize];
+ }
+
+ public List<float[]> ComputeFrom(float[] audio, int sampleRate)
+ {
+ int totalCount = (audio.Length - frameSize) / hopSize + 1;
+ List<float[]> mfccs = new List<float[]>(totalCount);
+
+ for (var i = 0; i < totalCount; i++)
+ {
+ mfccs.Add(new float[featureCount]);
+ }
+
+ var lastSample = audio.Length - frameSize;
+ for (int sample = 0, i = 0; sample <= lastSample; sample += hopSize, i++)
+ {
+ // 1. Framing
+ Buffer.BlockCopy(audio, sample * sizeof(float), block, 0, frameSize * sizeof(float));
+
+ for (var k = frameSize; k < blockSize; block[k++] = 0) { }
+
+ // 2. PreEmphasis
+ // PreEmphasis.PreEmphasize(ref block, 0.97f);
+
+ // 3. HammingWindow
+ window.Apply(block);
+
+ // 4. FFT
+ fft.Direct(block, spectrum);
+
+ // 5. MelFilterBank
+ filterBank.Apply(spectrum, melSpectrum);
+
+ // 6. DCT
+ dct.DirectNorm(melSpectrum, mfccs[i]);
+ }
+
+ return mfccs;
+ }
+ }
+
+ //DLL Interface
+ internal class Extractor
+ {
+ public static float[][] ComputeFrom(float[] audio, int samplingRate, float frameDuration, float hopDuration, int featureCount)
+ {
+ CustomMfccExtractor cme = new CustomMfccExtractor(samplingRate, frameDuration, hopDuration, featureCount);
+ List<float[]> mfccFeatures = cme.ComputeFrom(audio, samplingRate);
+
+ return mfccFeatures.ToArray();
+ }
+ }
+
+}
--- /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;
+
+namespace Tizen.AIAvatar
+{
+ internal class DCT
+ {
+ private int dctSize;
+ private int featureCount;
+
+ private float[][] dctMatrix;
+
+ public DCT(int filterBankSize, int featureCount = 12)
+ {
+ dctSize = filterBankSize;
+ this.featureCount = featureCount;
+
+ dctMatrix = new float[dctSize][];
+
+ float m = MathF.PI / (dctSize << 1);
+
+ for (var k = 0; k < dctSize; k++)
+ {
+ dctMatrix[k] = new float[dctSize];
+
+ for (var n = 0; n < dctSize; n++)
+ {
+ dctMatrix[k][n] = (float)(2 * Math.Cos(((n << 1) + 1) * k * m));
+ }
+ }
+ }
+
+ public void DirectNorm(float[] input, float[] output)
+ {
+
+ var norm0 = (float)Math.Sqrt(0.5f);
+ var norm = (float)Math.Sqrt(0.5f / dctSize);
+
+ for (var k = 0; k < featureCount; k++)
+ {
+ output[k] = 0.0f;
+ for (var n = 0; n < input.Length; n++)
+ {
+ output[k] += input[n] * dctMatrix[k][n];
+ }
+ output[k] *= norm;
+ }
+ output[0] *= norm0;
+ }
+ }
+}
\ No newline at end of file
--- /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;
+
+namespace Tizen.AIAvatar
+{
+ internal class FFT
+ {
+ private int fftSize;
+
+ private float[] re, im;
+ private float[] realSpectrum, imagSpectrum;
+ private float[] cosTbl, sinTbl;
+ private float[] ar, br, ai, bi;
+
+ public FFT(int size)
+ {
+ fftSize = size / 2;
+
+ // Precalculate FFT Parameter
+ re = new float[fftSize];
+ im = new float[fftSize];
+ realSpectrum = new float[fftSize + 1];
+ imagSpectrum = new float[fftSize + 1];
+
+ var tblSize = (int)Math.Log(fftSize, 2);
+
+ cosTbl = new float[tblSize];
+ sinTbl = new float[tblSize];
+
+ for (int i = 1, pos = 0; i < fftSize; i *= 2, pos++)
+ {
+ cosTbl[pos] = (float)Math.Cos(2 * Math.PI * i / fftSize);
+ sinTbl[pos] = (float)Math.Sin(2 * Math.PI * i / fftSize);
+ }
+
+ ar = new float[fftSize];
+ br = new float[fftSize];
+ ai = new float[fftSize];
+ bi = new float[fftSize];
+
+ var f = MathF.PI / fftSize;
+
+ for (var i = 0; i < fftSize; i++)
+ {
+ ar[i] = (float)(0.5 * (1 - Math.Sin(f * i)));
+ ai[i] = (float)(-0.5 * Math.Cos(f * i));
+ br[i] = (float)(0.5 * (1 + Math.Sin(f * i)));
+ bi[i] = (float)(0.5 * Math.Cos(f * i));
+ }
+ }
+
+ public void Direct(float[] input, float[] output)
+ {
+ for (int i = 0, k = 0; i < fftSize; i++)
+ {
+ re[i] = input[k++];
+ im[i] = input[k++];
+ }
+
+ var L = fftSize;
+ var M = fftSize >> 1;
+ var S = fftSize - 1;
+ var ti = 0;
+ while (L >= 2)
+ {
+ var l = L >> 1;
+ var u1 = 1.0f;
+ var u2 = 0.0f;
+ var c = cosTbl[ti];
+ var s = -sinTbl[ti];
+ ti++;
+ for (var j = 0; j < l; j++)
+ {
+ for (var i = j; i < fftSize; i += L)
+ {
+ var p = i + l;
+ var t1 = re[i] + re[p];
+ var t2 = im[i] + im[p];
+ var t3 = re[i] - re[p];
+ var t4 = im[i] - im[p];
+ re[p] = t3 * u1 - t4 * u2;
+ im[p] = t4 * u1 + t3 * u2;
+ re[i] = t1;
+ im[i] = t2;
+ }
+ var u3 = u1 * c - u2 * s;
+ u2 = u2 * c + u1 * s;
+ u1 = u3;
+ }
+ L >>= 1;
+ }
+ for (int i = 0, j = 0; i < S; i++)
+ {
+ if (i > j)
+ {
+ var t1 = re[j];
+ var t2 = im[j];
+ re[j] = re[i];
+ im[j] = im[i];
+ re[i] = t1;
+ im[i] = t2;
+ }
+ var k = M;
+ while (j >= k)
+ {
+ j -= k;
+ k >>= 1;
+ }
+ j += k;
+ }
+
+ realSpectrum[0] = re[0] * ar[0] - im[0] * ai[0] + re[0] * br[0] + im[0] * bi[0];
+ imagSpectrum[0] = im[0] * ar[0] + re[0] * ai[0] + re[0] * bi[0] - im[0] * br[0];
+
+ for (var k = 1; k < fftSize; k++)
+ {
+ realSpectrum[k] = re[k] * ar[k] - im[k] * ai[k] + re[fftSize - k] * br[k] + im[fftSize - k] * bi[k];
+ imagSpectrum[k] = im[k] * ar[k] + re[k] * ai[k] + re[fftSize - k] * bi[k] - im[fftSize - k] * br[k];
+ }
+
+ realSpectrum[fftSize] = re[0] - im[0];
+ imagSpectrum[fftSize] = 0;
+
+ for (int i = 0; i < fftSize; i++)
+ {
+ output[i] = realSpectrum[i] * realSpectrum[i] + imagSpectrum[i] * imagSpectrum[i];
+ }
+ }
+ }
+}
\ No newline at end of file
--- /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.Linq;
+
+namespace Tizen.AIAvatar
+{
+ internal struct bangDouble
+ {
+ public double left;
+ public double center;
+ public double right;
+
+ public bangDouble(double l, double c, double r)
+ {
+ left = l;
+ center = c;
+ right = r;
+ }
+
+ }
+
+ internal class FilterBank
+ {
+ private float[][] _filterBank;
+ private int _filterBankSize;
+
+ public FilterBank(int filterBankSize, int samplingRate, int blockSize)
+ {
+ _filterBankSize = filterBankSize;
+ var melBands = MelBands(filterBankSize, samplingRate);
+ _filterBank = Triangular(blockSize, samplingRate, melBands, HerzToMel);
+ }
+
+ public void Apply(float[] input, float[] output)
+ {
+ for (var i = 0; i < _filterBankSize; i++)
+ {
+ var sum = 0.0f;
+
+ for (var j = 0; j < input.Length; j++)
+ {
+ sum += _filterBank[i][j] * input[j];
+ }
+
+ output[i] = (float)Math.Log10(Math.Max(sum, float.Epsilon));
+ }
+ }
+
+ public static void Apply(float[][] filterBank, float[] spectrum, float[] filtered)
+ {
+ for (var i = 0; i < filterBank.Length; i++)
+ {
+ var en = 0.0f;
+
+ for (var j = 0; j < spectrum.Length; j++)
+ {
+ en += filterBank[i][j] * spectrum[j];
+ }
+
+ filtered[i] = en;
+ }
+ }
+
+ public static bangDouble[] MelBands(
+ int melFilterCount, int samplingRate, float lowFreq = 0, float highFreq = 0, bool overlap = true)
+ {
+ return UniformBands(HerzToMel, MelToHerz, melFilterCount, samplingRate, lowFreq, highFreq, overlap);
+ }
+
+ public static float[][] Triangular(int fftSize,
+ int samplingRate,
+ bangDouble[] frequencies,
+ Func<double, double> mapper = null)
+ {
+ if (mapper is null) mapper = x => x;
+
+ var herzResolution = (float)samplingRate / fftSize;
+ var herzFrequencies = Enumerable.Range(0, fftSize / 2 + 1)
+ .Select(f => f * herzResolution)
+ .ToArray();
+
+ var filterCount = frequencies.Length;
+ var filterBank = new float[filterCount][];
+
+ for (var i = 0; i < filterCount; i++)
+ {
+ filterBank[i] = new float[fftSize / 2 + 1];
+
+ var left = frequencies[i].left;
+ var center = frequencies[i].center;
+ var right = frequencies[i].right;
+
+ left = mapper(left);
+ center = mapper(center);
+ right = mapper(right);
+
+ var j = 0;
+ for (; mapper(herzFrequencies[j]) <= left; j++) ;
+ for (; mapper(herzFrequencies[j]) <= center; j++)
+ {
+ filterBank[i][j] = (float)((mapper(herzFrequencies[j]) - left) / (center - left));
+ }
+ for (; j < herzFrequencies.Length && mapper(herzFrequencies[j]) < right; j++)
+ {
+ filterBank[i][j] = (float)((right - mapper(herzFrequencies[j])) / (right - center));
+ }
+ }
+
+ return filterBank;
+ }
+
+ private static bangDouble[] UniformBands(
+ Func<double, double> scaleMapper,
+ Func<double, double> inverseMapper,
+ int filterCount,
+ int samplingRate,
+ float lowFreq = 0,
+ float highFreq = 0,
+ bool overlap = true)
+ {
+ if (lowFreq < 0) lowFreq = 0;
+ if (highFreq <= lowFreq) highFreq = samplingRate * 0.5f;
+
+ var startingFrequency = scaleMapper(lowFreq);
+ var frequencyTuples = new bangDouble[filterCount];
+
+ if (overlap)
+ {
+ var newResolution = (scaleMapper(highFreq) - scaleMapper(lowFreq)) / (filterCount + 1);
+ var frequencies = Enumerable.Range(0, filterCount + 2)
+ .Select(i => inverseMapper(startingFrequency + i * newResolution))
+ .ToArray();
+ for (var i = 0; i < filterCount; i++)
+ {
+ frequencyTuples[i].left = frequencies[i];
+ frequencyTuples[i].center = frequencies[i + 1];
+ frequencyTuples[i].right = frequencies[i + 2];
+ }
+ }
+ else
+ {
+ var newResolution = (scaleMapper(highFreq) - scaleMapper(lowFreq)) / filterCount;
+ var frequencies = Enumerable.Range(0, filterCount + 1)
+ .Select(i => inverseMapper(startingFrequency + i * newResolution))
+ .ToArray();
+
+ for (var i = 0; i < filterCount; i++)
+ {
+ frequencyTuples[i].left = frequencies[i];
+ frequencyTuples[i].center = (frequencies[i] + frequencies[i + 1]) / 2;
+ frequencyTuples[i].right = frequencies[i + 2];
+ }
+ }
+
+ return frequencyTuples;
+ }
+
+ public static double HerzToMel(double herz)
+ {
+ return 1127 * Math.Log(herz / 700 + 1);
+ }
+
+ public static double MelToHerz(double mel)
+ {
+ return (Math.Exp(mel / 1127) - 1) * 700;
+ }
+ }
+}
\ No newline at end of file
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
*
*/
-using System.ComponentModel;
+using System.Collections.Generic;
namespace Tizen.AIAvatar
{
- internal class BlendShapeVisemeInfo
+ internal interface IMfccExtractor
{
- internal Viseme name;
- internal BlendShapeValue[] values;
+ List<float[]> ComputeFrom(float[] samples, int samplingRate);
}
}
+
--- /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.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+ internal class PreEmphasis
+ {
+ internal static void PreEmphasize(ref float[] block, float value)
+ {
+ float prevSample = block[0];
+
+ for (int i = 0; i < block.Length; i++)
+ {
+ var result = block[i] - prevSample * value;
+ prevSample = block[i];
+ block[i] = result;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /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.Linq;
+
+namespace Tizen.AIAvatar
+{
+ internal class Window
+ {
+ private float[] _window;
+
+ public Window(int size)
+ {
+ _window = Hamming(size);
+ }
+
+ public void Apply(float[] block)
+ {
+ if (block.Length < _window.Length) return;
+
+ for (int i = 0; i < _window.Length; i++)
+ {
+ block[i] *= _window[i];
+ }
+ }
+
+ public static float[] Hamming(int length)
+ {
+ var n = 2 * Math.PI / (length - 1);
+ return Enumerable.Range(0, length)
+ .Select(i => 0.54f - 0.46f * Math.Cos(i * n))
+ .Select(v => (float)v)
+ .ToArray();
+ }
+ }
+}
\ No newline at end of file
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
namespace Tizen.AIAvatar
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal enum NodeType
+ internal interface ISingleShotModel
{
+
[EditorBrowsable(EditorBrowsableState.Never)]
- HeadGeo,
+ public void SetTensorData(int index, byte[] buffer);
[EditorBrowsable(EditorBrowsableState.Never)]
- MouthGeo,
+ public byte[] GetTensorData(int index);
[EditorBrowsable(EditorBrowsableState.Never)]
- EyelashGeo
+ public void Invoke();
}
}
using System;
using System.Collections.Generic;
-using System.ComponentModel;
-using System.Text;
-using Tizen.AIAvatar;
+using System.Linq;
namespace Tizen.AIAvatar
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public class LipSyncData : IAnimationModuleData
+ internal static class SoftmaxLinqExtension
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public byte[] AudioFile { get; set; }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public int SampleRate { get; set; }
+ internal static IEnumerable<float> SoftMax(this IEnumerable<float> source)
+ {
+ var exp = source.Select(x => MathF.Exp(x)).ToArray();
+ var sum = exp.Sum();
+ return exp.Select(x => x / sum);
+ }
}
}
-using System;
-using System.Collections.Generic;
+/*
+ * 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;
-using System.Text;
using Tizen.MachineLearning.Inference;
using static Tizen.AIAvatar.AIAvatar;
--- /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 Newtonsoft.Json;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Tizen.AIAvatar
+{
+ internal enum Viseme
+ {
+ sil, AE, Ah, B_M_P, Ch_J, EE, Er, IH, Oh, W_OO, S_Z, F_V, TH,
+ T_L_D_N, K_G_H_NG, R
+ };
+
+ internal class AnimationConverter
+ {
+ private Dictionary<string, string> VowelToViseme
+ = new Dictionary<string, string> {
+ { "A", "Ah" },
+ { "E", "AE" },
+ { "I", "EE" },
+ { "O", "R" },
+ { "ER", "R" },
+ { "U", "W_OO" },
+ { "HM", "B_M_P" },
+ { "sil", "sil" }
+ };
+
+ private AnimationKeyFrame _animationKeyFrame;
+ private BlendShapeInfo _visemBlendShapeInfo;
+ private Dictionary<string, BlendShapeValue[]> _visemeMap;
+
+ private bool _isInitialized;
+
+ public AnimationConverter() { }
+
+ public void InitializeVisemeInfo(string info_path)
+ {
+ try
+ {
+ StreamReader v = new StreamReader(info_path);
+ var jsonString = v.ReadToEnd();
+
+ _visemBlendShapeInfo = JsonConvert.DeserializeObject<BlendShapeInfo>(jsonString);
+ _visemeMap = _visemBlendShapeInfo.GetVisemeMap();
+
+ var nodeNames = _visemBlendShapeInfo.GetNodeNames();
+ var blendShapeCounts = _visemBlendShapeInfo.GetBlendShapeCounts();
+ var blendShapeKeyFormat = _visemBlendShapeInfo.blendShape.keyFormat;
+
+ _animationKeyFrame = new AnimationKeyFrame(nodeNames,
+ blendShapeCounts,
+ blendShapeKeyFormat);
+ _isInitialized = true;
+ }
+ catch (Exception)
+ {
+ throw new FailedPersonalizeException(info_path);
+ }
+ }
+
+ public AnimationKeyFrame ConvertVowelsToAnimation(string[] vowels,
+ float stepDuration)
+ {
+ if (!_isInitialized) throw new NotInitializedException();
+
+ _animationKeyFrame.ClearAnimation();
+ ConvertVowelsToVisemes(vowels, out var visemes);
+ ConvertVisemesToAnimationKeyFrame(visemes, stepDuration);
+
+ return _animationKeyFrame;
+ }
+
+ public AnimationKeyFrame ConvertVowelsToAnimationMic(string[] vowels,
+ float stepDuration)
+ {
+ if (!_isInitialized) throw new NotInitializedException();
+
+ _animationKeyFrame.ClearAnimation();
+ ConvertVowelsToVisemes(vowels, out var visemes);
+ ConvertVisemesToAnimationKeyFrameMic(visemes, stepDuration);
+
+ return _animationKeyFrame;
+ }
+
+ private void ConvertVowelsToVisemes(in string[] vowels,
+ out string[] visemes)
+ {
+ visemes = new string[vowels.Length];
+
+ for (var i = 0; i < vowels.Length; i++)
+ {
+ if (!VowelToViseme.TryGetValue(vowels[i], out visemes[i]))
+ {
+ throw new InvalidVowelTypeException(vowels[i]);
+ }
+ }
+ }
+
+ private void ConvertVisemesToAnimationKeyFrame(in string[] visemes,
+ float stepDuration)
+ {
+ float animationTime = visemes.Length * stepDuration;
+ _animationKeyFrame.SetAnimationTime(animationTime);
+
+ for (int i = 0; i < visemes.Length; i++)
+ {
+ float timeStamp = GetTimeStamp(i, stepDuration) / animationTime;
+
+ foreach (var info in _visemeMap[visemes[i]])
+ {
+ _animationKeyFrame.AddKeyFrame(info.nodeName,
+ info.blendIndex,
+ timeStamp,
+ info.blendValue);
+ }
+ }
+ }
+
+ private void ConvertVisemesToAnimationKeyFrameMic(in string[] visemes,
+ float stepDuration)
+ {
+ float animationTime = (visemes.Length - 1) * stepDuration;
+ _animationKeyFrame.SetAnimationTime(animationTime);
+
+ for (int i = 0; i < visemes.Length; i++)
+ {
+ float timeStamp = GetTimeStamp(i, stepDuration) / animationTime;
+
+ foreach (var info in _visemeMap[visemes[i]])
+ {
+ _animationKeyFrame.AddKeyFrame(info.nodeName,
+ info.blendIndex,
+ timeStamp,
+ info.blendValue);
+ }
+ }
+ }
+
+ private float GetTimeStamp(int idx, float stepDuration)
+ {
+ if (idx > 0)
+ return (idx * stepDuration) - (stepDuration / 2.0f);
+ else
+ return 0;
+ }
+ }
+}
\ No newline at end of file
--- /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.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+ internal class KeyFrame
+ {
+ public KeyFrame(float t, float v)
+ {
+ time = t;
+ value = v;
+ }
+ public float time;
+ public float value;
+ }
+
+ internal class AnimationKeyFrame
+ {
+ private Dictionary<string, List<KeyFrame>[]> _animationKeyFrames;
+
+ public string[] NodeNames { get; private set; }
+ public int[] BlendShapeCounts { get; private set; }
+ public string BlendShapeKeyFormat { get; private set; }
+ public float AnimationTime { get; private set; }
+
+ public AnimationKeyFrame(string[] nodeNames,
+ int[] blendShapeCounts,
+ string blendShapeKeyFormat)
+ {
+ _animationKeyFrames = new Dictionary<string, List<KeyFrame>[]>();
+ NodeNames = nodeNames;
+ BlendShapeCounts = blendShapeCounts;
+ BlendShapeKeyFormat = blendShapeKeyFormat;
+
+ InitializeAnimation(nodeNames, blendShapeCounts);
+ }
+
+ public void SetAnimationTime(float animationTime)
+ {
+ AnimationTime = animationTime;
+ }
+
+ public List<KeyFrame> GetKeyFrames(string nodeName, int blendIndex)
+ {
+ return _animationKeyFrames[nodeName][blendIndex];
+ }
+
+ public void AddKeyFrame(string nodeName, int blendIndex, float time, float value)
+ {
+ _animationKeyFrames[nodeName][blendIndex].Add(new KeyFrame(time, value));
+ }
+
+ public void AddKeyFrame(string nodeName, int blendIndex, KeyFrame value)
+ {
+ _animationKeyFrames[nodeName][blendIndex].Add(value);
+ }
+
+ public void InitializeAnimation(string[] nodeNames, int[] blendShapeCounts)
+ {
+ ClearAnimation();
+
+ for (int i = 0; i < nodeNames.Length; i++)
+ {
+ var nodeName = nodeNames[i];
+ var blendShapeCount = blendShapeCounts[i];
+
+ _animationKeyFrames.Add(nodeName, new List<KeyFrame>[blendShapeCount]);
+
+ for (int j = 0; j < blendShapeCount; j++)
+ {
+ _animationKeyFrames[nodeName][j] = new List<KeyFrame>();
+ }
+ }
+ }
+
+ public void ClearAnimation()
+ {
+ foreach (KeyValuePair<string, List<KeyFrame>[]> kvp in _animationKeyFrames)
+ {
+ foreach (List<KeyFrame> kf in kvp.Value)
+ {
+ kf.Clear();
+ }
+ }
+ }
+ }
+}
--- /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.Collections.Generic;
+
+namespace Tizen.AIAvatar
+{
+ internal class BlendShapeInfo
+ {
+ public BlendShapeModelInfo blendShape;
+ public BlendShapeVisemeInfo[] visemes;
+
+ public BlendShapeInfo() { }
+
+ public string[] GetNodeNames()
+ {
+ return blendShape.nodeNames;
+ }
+
+ public int[] GetBlendShapeCounts()
+ {
+ return blendShape.blendShapeCount;
+ }
+
+ public Dictionary<string, BlendShapeValue[]> GetVisemeMap()
+ {
+ Dictionary<string, BlendShapeValue[]> visemeMap
+ = new Dictionary<string, BlendShapeValue[]>();
+
+ foreach (var visemeInfo in this.visemes)
+ {
+ visemeMap.Add(visemeInfo.name, visemeInfo.values);
+ }
+
+ return visemeMap;
+ }
+ }
+
+ internal class BlendShapeModelInfo
+ {
+ public string keyFormat;
+ public string[] nodeNames;
+ public int[] blendShapeCount;
+
+ public BlendShapeModelInfo(string keyFormat, string[] nodeNames, int[] blendShapeCount)
+ {
+ this.keyFormat = keyFormat;
+ this.nodeNames = nodeNames;
+ this.blendShapeCount = blendShapeCount;
+ }
+ }
+
+ internal class BlendShapeVisemeInfo
+ {
+ public string name;
+ public BlendShapeValue[] values;
+ }
+
+ internal class BlendShapeValue
+ {
+ public string nodeName;
+ public int blendIndex;
+ public float blendValue;
+ }
+}
--- /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;
+
+namespace Tizen.AIAvatar
+{
+ internal class InvalidVowelTypeException : Exception
+ {
+ public InvalidVowelTypeException() { }
+
+ public InvalidVowelTypeException(string name)
+ : base($"Not supported vowel type, {name}") { }
+ }
+
+ internal class FailedPersonalizeException : Exception
+ {
+ public FailedPersonalizeException() { }
+
+ public FailedPersonalizeException(string name)
+ : base($"Failed to personalize, file_path : {name}") { }
+ }
+
+ internal class NotInitializedException : Exception
+ {
+ public NotInitializedException()
+ : base($"Animation Converter should be initialized with viseme_info") { }
+ }
+}
--- /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.Collections.Generic;
+using System.Linq;
+
+namespace Tizen.AIAvatar
+{
+ internal class VowelClassifier
+ {
+ private readonly int vowelForecastRange = 6;
+ private readonly string[] vowelName = { "A", "E", "I", "O", "U", "HM", "ER" };
+
+ private readonly int sampleRate;
+ private readonly int featureCount;
+
+ private float stepTime = 0.0f;
+ private const int DefaultFeatureMeanCount = 8;
+
+ private CustomMfccExtractor mfccExtractor;
+
+
+ internal VowelClassifier(int sampleRate, float frameDuration = 0.025f, float hopDuration = 0.01f, int featureCount = 12)
+ {
+ this.sampleRate = sampleRate;
+ this.featureCount = featureCount;
+ stepTime = (float)(hopDuration * DefaultFeatureMeanCount);
+ mfccExtractor = new CustomMfccExtractor(sampleRate, frameDuration, hopDuration, featureCount);
+ }
+
+ public float GetStepTime()
+ {
+ return stepTime;
+ }
+
+
+ public string[] Inference(byte[] audio, ISingleShotModel model)
+ {
+ int length = PreprocessInput(audio, out float[] features, out List<float> audioEnergy);
+ var outputData = InferenceModel(features, length, model);
+ var result = ProcessOutput(outputData, audioEnergy);
+
+ return result.ToArray();
+ }
+
+ public int PreprocessInput(byte[] audioByte, out float[] flattenedArray, out List<float> audioEnergy)
+ {
+ Utils.ConvertAudioToFloat(audioByte, out var audio);
+
+ var mfccFeatures = mfccExtractor.ComputeFrom(audio, sampleRate);
+
+ int featureLength = (int)Math.Ceiling((double)mfccFeatures.Count / DefaultFeatureMeanCount);
+ flattenedArray = new float[featureLength * featureCount];
+ audioEnergy = new List<float>();
+
+ for (int i = 0; i < featureLength; i++)
+ {
+ CalculateFeatureMean(mfccFeatures, out var featureMean, out var energy, i * DefaultFeatureMeanCount);
+ Array.Copy(featureMean, 0, flattenedArray, i * featureCount, featureCount);
+ audioEnergy.Add(energy);
+ }
+
+ return featureLength;
+ }
+
+ public List<float[]> InferenceModel(float[] input, int length, ISingleShotModel model)
+ {
+ byte[] inputBuffer = new byte[4 * 12 * 1 * 1];
+ byte[] outputBuffer;
+
+ int srcOffset = 0;
+ List<float[]> fullOutput = new List<float[]>();
+
+ for (int i = 0; i < length; i++)
+ {
+ float[] output = new float[7];
+
+ Buffer.BlockCopy(input, srcOffset, inputBuffer, 0, inputBuffer.Length);
+ srcOffset += inputBuffer.Length;
+
+ model.SetTensorData(0, inputBuffer);
+
+ model.Invoke();
+
+ outputBuffer = model.GetTensorData(0);
+
+ Buffer.BlockCopy(outputBuffer, 0, output, 0, outputBuffer.Length);
+
+ fullOutput.Add(output);
+
+ }
+
+ return fullOutput;
+ }
+
+ private List<string> ProcessOutput(List<float[]> outputData, List<float> audioEnergy)
+ {
+ var result = new List<string>();
+
+ for (int i = 0; i < outputData.Count; i++)
+ {
+ // Softmax 연산 수행
+ if (audioEnergy[i] > -1.0f)
+ {
+ var scores = Enumerable.Range(0, vowelForecastRange).
+ Select(j => outputData[i][j]).SoftMax().ToArray();
+ int maxIndex = Array.IndexOf(scores, scores.Max());
+ result.Add(vowelName[maxIndex]);
+ }
+ else
+ {
+ result.Add("sil");
+ }
+
+ }
+
+ return result;
+ }
+
+ private void CalculateFeatureMean(in List<float[]> features,
+ out float[] featureMean,
+ out float energy,
+ int offset)
+ {
+ featureMean = new float[featureCount];
+ int featureLength = (DefaultFeatureMeanCount < features.Count - offset
+ ? DefaultFeatureMeanCount
+ : features.Count - offset);
+
+ float sum = 0f;
+ for (int fc = 0; fc < featureCount; fc++)
+ {
+ for (int dc = offset; dc < offset + DefaultFeatureMeanCount && dc < features.Count; dc++)
+ {
+ featureMean[fc] += features[dc][fc];
+ }
+ featureMean[fc] /= featureLength;
+ sum += featureMean[fc];
+ }
+ energy = sum / featureCount;
+ }
+ }
+}
--- /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.Collections.Generic;
+
+using static Tizen.AIAvatar.AIAvatar;
+
+namespace Tizen.AIAvatar
+{
+ internal class VowelConverter
+ {
+ private TFVowel6 vowelClassfierModel = null;
+ private VowelClassifier vowelClassifier = null;
+ private Dictionary<int, VowelClassifier> vowelClassifiers;
+ private AnimationConverter animationConverter = new AnimationConverter();
+
+ internal VowelConverter()
+ {
+ vowelClassifiers = new Dictionary<int, VowelClassifier>();
+ vowelClassifier = GetVowelClassifier(CurrentAudioOptions.SampleRate);
+ vowelClassfierModel = new TFVowel6(new int[4] { 12, 1, 1, 1 }, new int[4] { 7, 1, 1, 1 });
+ animationConverter.InitializeVisemeInfo(VisemeInfo);
+ }
+
+ internal AnimationKeyFrame CreateKeyFrames(string[] vowels, int sampleRate, bool isMic = false)
+ {
+ vowelClassifier = GetVowelClassifier(sampleRate);
+
+ if (isMic)
+ {
+ return animationConverter.ConvertVowelsToAnimationMic(vowels, vowelClassifier.GetStepTime());
+ }
+ else
+ {
+ return animationConverter.ConvertVowelsToAnimation(vowels, vowelClassifier.GetStepTime());
+ }
+ }
+
+ internal AnimationKeyFrame CreateKeyFrames(byte[] audioData, int sampleRate, bool isMic = false)
+ {
+ vowelClassifier = GetVowelClassifier(sampleRate);
+
+ if (vowelClassifier == null)
+ {
+ Log.Error(LogTag, "Failed to play Buffer");
+ return null;
+ }
+ var vowels = PredictVowels(audioData);
+ Log.Info(LogTag, $"vowelRecognition: {string.Join(", ", vowels)}");
+
+ if (isMic) return animationConverter.ConvertVowelsToAnimationMic(vowels, vowelClassifier.GetStepTime());
+ else return animationConverter.ConvertVowelsToAnimation(vowels, vowelClassifier.GetStepTime());
+ }
+
+ internal string[] PredictVowels(byte[] audioData)
+ {
+ var vowels = vowelClassifier.Inference(audioData, vowelClassfierModel);
+ return vowels;
+ }
+
+ internal VowelClassifier GetVowelClassifier(int sampleRate)
+ {
+ if (vowelClassifiers.ContainsKey(sampleRate))
+ {
+ return vowelClassifiers[sampleRate];
+ }
+ else
+ {
+ vowelClassifiers[sampleRate] = new VowelClassifier(sampleRate);
+ return vowelClassifiers[sampleRate];
+ }
+ }
+ }
+}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/// <summary>
/// Provides the ability to audio
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
- public class AudioOptions
+ internal class AudioOptions
{
private int sampleRate;
private AudioChannel channel;
/// <param name="sampleRate">the audio sample rate (8000 ~ 192000Hz)</param>
/// <param name="channel">the audio channel type.</param>
/// <param name="sampleType">the audio sample type.</param>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public AudioOptions(int sampleRate, AudioChannel channel, AudioSampleType sampleType)
{
/// <summary>
/// The audio sample rate (8000 ~ 192000Hz)
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public int SampleRate { get => sampleRate; set => sampleRate = value; }
/// <summary>
/// The audio channel type
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public AudioChannel Channel { get => channel; set => channel = value; }
/// <summary>
/// The audio sample type
/// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
[EditorBrowsable(EditorBrowsableState.Never)]
public AudioSampleType SampleType { get => sampleType; set => sampleType = value; }
}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
namespace Tizen.AIAvatar
{
- internal class AudioPlayer
+ internal class AudioPlayer : IDisposable
{
private AudioPlayback audioPlayback;
private MemoryStream audioStream;
{
if (audioPlayback != null)
{
- DestroyAudioPlayback();
+ Destroy();
}
if (sampleRate == 0)
{
catch (Exception e)
{
Log.Error(LogTag, $"Failed to create AudioPlayback. {e.Message}");
- return;
}
if (audioPlayback != null)
if (audioPlayback != null)
{
audioPlayback.Pause();
- DestroyAudioPlayback();
+ Destroy();
}
else
{
}
}
- internal void Destroy()
+ public void Dispose()
{
- DestroyAudioPlayback();
+ Destroy();
+
+ audioStream?.Flush();
+ audioStream?.Dispose();
+ audioStream = null;
}
- private void DestroyAudioPlayback()
+ private void Destroy()
{
audioPlayback?.Unprepare();
audioPlayback?.Dispose();
using System;
using System.Linq;
-using System.Text;
using Tizen.Multimedia;
using Tizen.NUI;
using static Tizen.AIAvatar.AIAvatar;
namespace Tizen.AIAvatar
{
- internal class AudioRecorder
+ internal class AudioRecorder : IDisposable
{
private const string privilegeForRecording = "http://tizen.org/privilege/recorder";
private Timer audioRecordingTimer;
private Action audioRecdingAction;
- private Action<byte[],int > bufferAction;
+ private Action<byte[], int> bufferAction;
private static AudioRecorder instance;
desiredBufferLength = (int)(CurrentAudioOptions.SampleRate * desiredBufferDuration * 2);
}
-
- internal void InitMic(BlendShapePlayer animator, uint recordingTime = 160)
+ internal void InitializeMic(LipSyncer lipSyncer, uint recordingTime = 160)
{
audioRecordingTimer = new Timer(recordingTime);
- if (animator != null)
+ if (lipSyncer != null)
{
- //TODO : Connection MIC
- var lipSyncer = (animator.GetAnimationModule(AnimationModuleType.LipSyncer) as LipSyncer);
- if(lipSyncer != null)
- {
- Tizen.Log.Error(LogTag, "LipSyncer of animator is null");
- return;
- }
- this.audioRecdingAction = lipSyncer.OnRecodingTick;
- this.bufferAction = lipSyncer.OnRecordBufferChanged;
-
- BufferChanged += OnRecordBufferChanged;
- audioRecordingTimer.Tick += AudioRecordingTimerTick;
+ Tizen.Log.Error(LogTag, "LipSyncer of animator is null");
+ return;
}
+ this.audioRecdingAction = lipSyncer.OnRecodingTick;
+ this.bufferAction = lipSyncer.OnRecordBufferChanged;
+
+ BufferChanged += OnRecordBufferChanged;
+ audioRecordingTimer.Tick += AudioRecordingTimerTick;
}
- internal void DeinitMic()
+ internal void DeinitializeMic()
{
StopRecording();
BufferChanged -= OnRecordBufferChanged;
audioRecdingAction?.Invoke();
return true;
}
+
+ public void Dispose()
+ {
+ throw new NotImplementedException();
+ }
}
}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
using System;
using System.Collections.Generic;
+using System.Linq;
using Tizen.Uix.Tts;
-using System.Runtime.InteropServices;
using static Tizen.AIAvatar.AIAvatar;
-using System.Linq;
-using Tizen.NUI;
namespace Tizen.AIAvatar
{
- internal class TTSLipSyncer
+ internal class TTSControllerEventArgs : EventArgs
{
+ public TTSControllerEventArgs()
+ {
+ }
+
+ public TTSControllerEventArgs(byte[] audioData, int sampleRate)
+ {
+ //AudioData = audioData;
+ AudioData = new byte[audioData.Length];
+ Buffer.BlockCopy(audioData, 0, AudioData, 0, audioData.Length);
+ SampleRate = sampleRate;
+ }
+
+ public byte[] AudioData
+ {
+ get;
+ internal set;
+ }
- private Avatar currentAvatar;
+ public int SampleRate
+ {
+ get;
+ internal set;
+ }
+ }
+ internal class TTSController : IDisposable
+ {
private List<UtteranceText> textList;
private TtsClient ttsHandle;
private VoiceInfo voiceInfo;
private int audioLength;
private bool isAsyncLipStarting;
- private AsyncLipSyncer lipSyncer;
+ internal event EventHandler PlayReadyCallback;
+ internal event EventHandler<TTSControllerEventArgs> PreparedSyncText;
+ internal event EventHandler<TTSControllerEventArgs> StoppedTTS;
+
+
+ internal event EventHandler<TTSControllerEventArgs> UpdatedBuffer;
- internal TTSLipSyncer(AsyncLipSyncer lipSyncer)
+ internal TTSController()
{
- this.lipSyncer = lipSyncer;
InitTts();
}
- ~TTSLipSyncer()
+ ~TTSController()
{
DeinitTts();
}
- internal event EventHandler PlayReadyCallback;
-
internal TtsClient TtsHandle
{
get { return ttsHandle; }
foreach (var supportedVoice in supportedVoices)
{
Log.Info(LogTag, $"{supportedVoice.Language} & {supportedVoice.VoiceType} is supported");
- voiceInfoList.Add(new VoiceInfo() { Lang = supportedVoice.Language, Type = supportedVoice.VoiceType });
+ voiceInfoList.Add(new VoiceInfo() { Language = supportedVoice.Language, Type = (VoiceType)supportedVoice.VoiceType });
}
return voiceInfoList;
}
var supportedVoices = ttsHandle.GetSupportedVoices();
foreach (var supportedVoice in supportedVoices)
{
- if (supportedVoice.Language.Equals(voiceInfo.Lang) && (supportedVoice.VoiceType == voiceInfo.Type))
+ if (supportedVoice.Language.Equals(voiceInfo.Language) && ((VoiceType)supportedVoice.VoiceType == voiceInfo.Type))
{
- Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is supported");
+ Log.Info(LogTag, $"{voiceInfo.Language} & {voiceInfo.Type} is supported");
return true;
}
}
internal void AddText(string txt, VoiceInfo voiceInfo)
{
- if (voiceInfo.Lang == null || voiceInfo.Type == null)
+ if (voiceInfo.Language == null)
{
Log.Error(LogTag, "VoiceInfo's value is null");
}
}
var temp = new UtteranceText();
temp.Text = txt;
- temp.UttID = ttsHandle.AddText(txt, voiceInfo.Lang, (int)voiceInfo.Type, 0);
+ temp.UttID = ttsHandle.AddText(txt, voiceInfo.Language, (int)voiceInfo.Type, 0);
try
{
textList.Add(temp);
Play(true);
}
+
internal bool PlayPreparedText()
{
if (byteList != null && byteList.Count != 0)
{
Log.Info(LogTag, "PlayPreparedText TTS");
- currentAvatar?.AvatarAnimator?.PlayLipSync(byteList.ToArray(), sampleRate);
+
+ PreparedSyncText?.Invoke(this, new TTSControllerEventArgs(byteList.ToArray(), sampleRate));
return true;
}
return false;
return;
}
ttsHandle.Stop();
- currentAvatar?.AvatarAnimator?.StopLipSync();
- }
-
- private void InitTts()
- {
- try
- {
- ttsHandle = new TtsClient();
-
- // Register Callbacks
- ttsHandle.DefaultVoiceChanged += TtsDefaultVoiceChangedCallback;
- ttsHandle.EngineChanged += TtsEngineChangedCallback;
- ttsHandle.ErrorOccurred += TtsErrorOccuredCallback;
- ttsHandle.StateChanged += TtsStateChangedCallback;
- ttsHandle.UtteranceCompleted += TtsUtteranceCompletedCallback;
- ttsHandle.UtteranceStarted += TtsUtteranceStartedCallback;
-
- ttsHandle.SynthesizedPcm += TtsSyntheiszedPCM;
- ttsHandle.PlayingMode = PlayingMode.ByClient;
-
- ttsHandle.Prepare();
-
- voiceInfo = new VoiceInfo
- {
- Lang = ttsHandle.DefaultVoice.Language,
- Type = ttsHandle.DefaultVoice.VoiceType
- };
-
- textList = new List<UtteranceText>();
- Log.Info(LogTag, voiceInfo.Lang + ", " + voiceInfo.Type.ToString());
-
- }
- catch (Exception e)
- {
- Log.Error(LogTag, "[ERROR] Fail to prepare Tts");
- Log.Error(LogTag, e.Message);
- }
+ StoppedTTS?.Invoke(this, new TTSControllerEventArgs());
}
internal void DeinitTts()
byteList.Clear();
byteList = null;
}
- currentAvatar = null;
}
catch (Exception e)
{
}
}
- private void TtsSyntheiszedPCM(object sender, SynthesizedPcmEventArgs e)
+ private void InitTts()
{
+ try
+ {
+ ttsHandle = new TtsClient();
+
+ // Register Callbacks
+ ttsHandle.DefaultVoiceChanged += TtsDefaultVoiceChangedCallback;
+ ttsHandle.EngineChanged += TtsEngineChangedCallback;
+ ttsHandle.ErrorOccurred += TtsErrorOccuredCallback;
+ ttsHandle.StateChanged += TtsStateChangedCallback;
+ ttsHandle.UtteranceCompleted += TtsUtteranceCompletedCallback;
+ ttsHandle.UtteranceStarted += TtsUtteranceStartedCallback;
+ ttsHandle.SynthesizedPcm += TtsSyntheiszedPCM;
+ ttsHandle.PlayingMode = PlayingMode.ByClient;
+
+ ttsHandle.Prepare();
+
+ voiceInfo = new VoiceInfo
+ {
+ Language = ttsHandle.DefaultVoice.Language,
+ Type = (VoiceType)ttsHandle.DefaultVoice.VoiceType
+ };
+
+ textList = new List<UtteranceText>();
+ Log.Info(LogTag, voiceInfo.Language + ", " + voiceInfo.Type.ToString());
+
+ }
+ catch (Exception e)
+ {
+ Log.Error(LogTag, "[ERROR] Fail to prepare Tts");
+ Log.Error(LogTag, e.Message);
+ }
+ }
+
+ private void TtsSyntheiszedPCM(object sender, SynthesizedPcmEventArgs e)
+ {
var dataSize = e.Data.Length;
var audio = new byte[dataSize];
sampleRate = e.SampleRate;
audioTailLength = (int)(sampleRate * audioTailLengthFactor * audioBufferMultiflier);
audioTailBuffer = new byte[audioTailLength];
PlayReadyCallback?.Invoke(null, EventArgs.Empty);
- InitAsyncBuffer();
- lipSyncer.SampleRate = sampleRate;
+ //InitAsyncBuffer();
}
break;
case SynthesizedPcmEvent.Continue://continue
if (recordedBuffer.Length >= desiredBufferLength)
{
Tizen.Log.Error(LogTag, "Current recordbuffer length :" + recordedBuffer.Length);
- UpdateBuffer(recordedBuffer, sampleRate);
-
+ //UpdateBuffer(recordedBuffer, sampleRate);
+
Buffer.BlockCopy(recordedBuffer, recordedBuffer.Length - audioTailLength, audioTailBuffer, 0, audioTailLength);
recordedBuffer = Array.Empty<byte>();
if (!isPrepared)
{
//Play voice immediately
- //PlayPreparedText();
+ PlayPreparedText();
}
else
{
}
}
else
- {
- lipSyncer.SetFinishAsyncLip(true);
+ {//async
+ //FinishedSynthesizedPcm?.Invoke(null, EventArgs.Empty);
+ //lipSyncer.SetFinishAsyncLip(true);
}
break;
case SynthesizedPcmEvent.Fail: //fail
Log.Debug(LogTag, "Default voice is changed from (" + e.Previous + ") to (" + e.Current + ")");
}
- internal void InitAsyncBuffer()
+ private void InitAsyncBuffer()
{
+ /*
+ InitedAsyncBuffer?.Invoke(null, EventArgs.Empty);
if (!lipSyncer.IsAsyncInit)
{
audioLength = (int)(sampleRate * 0.16f * 2f);
lipSyncer.SetFinishAsyncLip(false);
isAsyncLipStarting = false;
- }
+ }*/
}
- internal void UpdateBuffer(byte[] recordBuffer, int sampleRate)
+ private void UpdateBuffer(byte[] recordBuffer, int sampleRate)
{
+ UpdatedBuffer?.Invoke(this, new TTSControllerEventArgs(recordBuffer, sampleRate));
+ /*
if (lipSyncer != null)
{
Log.Error(LogTag, "OnTTSBufferChanged");
else
{
Log.Error(LogTag, "avatarLipSyncer is null");
- }
+ }*/
+ }
+
+ public void Dispose()
+ {
+ ttsHandle.Stop();
+ ttsHandle.Dispose();
+ ttsHandle = null;
}
}
}
--- /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;
+
+namespace Tizen.AIAvatar
+{
+ internal struct UtteranceText : IEquatable<UtteranceText>
+ {
+ private string text;
+ private int uttID;
+
+ public string Text { get => text; set => text = value; }
+ public int UttID { get => uttID; set => uttID = value; }
+
+ public override bool Equals(object obj) => obj is VoiceInfo other && this.Equals(other);
+
+ public bool Equals(UtteranceText other) => Text == other.Text && UttID == other.UttID;
+
+ public static bool operator ==(UtteranceText lhsUtternaceText, UtteranceText rhsUtternaceText) => lhsUtternaceText.Equals(rhsUtternaceText);
+
+ public static bool operator !=(UtteranceText lhsUtternaceText, UtteranceText rhsVoiceInfo) => !lhsUtternaceText.Equals(rhsVoiceInfo);
+
+ public override int GetHashCode() => (Text, UttID).GetHashCode();
+ }
+}
--- /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.AIAvatar
+{
+ /// <summary>
+ /// VoiceInfo stores information about a voice.
+ /// The 'Language' field stores the language of the voice
+ /// The 'Type' field stores the type of the voice.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public struct VoiceInfo : IEquatable<VoiceInfo>
+ {
+ private string language;
+ private VoiceType type;
+
+ /// <summary>
+ /// Gets or sets the language of the voice.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string Language { get => language; set => language = value; }
+
+ /// <summary>
+ /// Gets or sets the type of the voice.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VoiceType Type { get => type; set => type = value; }
+
+ /// <summary>
+ /// Determines whether the specified object is equal to the current object.
+ /// </summary>
+ /// <param name="obj">The object to compare with the current object.</param>
+ /// <returns>true if equal VoiceInfo, else false.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj) => obj is VoiceInfo other && this.Equals(other);
+
+ /// <summary>
+ /// Determines whether the specified object is equal to the current object.
+ /// </summary>
+ /// <param name="other">The VoiceInfo to compare with the current VoiceInfo.</param>
+ /// <returns>true if equal VoiceInfo, else false.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool Equals(VoiceInfo other) => Language == other.Language && Type == other.Type;
+
+ /// <summary>
+ /// The == operator.
+ /// </summary>
+ /// <param name="lhsVoiceInfo">VoiceInfo to compare</param>
+ /// <param name="rhsVoiceInfo">VoiceInfo to be compared</param>
+ /// <returns>true if VoiceInfo are equal</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool operator ==(VoiceInfo lhsVoiceInfo, VoiceInfo rhsVoiceInfo) => lhsVoiceInfo.Equals(rhsVoiceInfo);
+
+ /// <summary>
+ /// The != operator.
+ /// </summary>
+ /// <param name="lhsVoiceInfo">VoiceInfo to compare</param>
+ /// <param name="rhsVoiceInfo">VoiceInfo to be compared</param>
+ /// <returns>true if VoiceInfo are not equal</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool operator !=(VoiceInfo lhsVoiceInfo, VoiceInfo rhsVoiceInfo) => !lhsVoiceInfo.Equals(rhsVoiceInfo);
+
+ /// <summary>
+ /// Gets the hash code of this VoiceInfo.
+ /// </summary>
+ /// <returns>The hash code.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode() => (Language, Type).GetHashCode();
+ }
+}
*/
using System.ComponentModel;
-using Tizen.NUI.Scene3D;
namespace Tizen.AIAvatar
{
+ /// <summary>
+ /// VoiceType is an enum that represents various types of voices.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public class MotionBehaviorData : IAnimationModuleData
+ public enum VoiceType
{
+ /// <summary>
+ /// Automatically determines the best voice to use based on available options.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public MotionDataType Type { get; set; } = MotionDataType.AnimationInfo;
+ Auto = 0,
+ /// <summary>
+ /// Selects a male voice for speech synthesis.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public AnimationInfo AnimationInfo { get; set; }
+ Male = 1,
+ /// <summary>
+ /// Selects a female voice for speech synthesis.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public MotionData MotionData { get; set; }
+ Female = 2,
+ /// <summary>
+ /// Selects a child's voice for speech synthesis.
+ /// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
- public int Duration { get; set; } = 3000;
- [EditorBrowsable(EditorBrowsableState.Never)]
- public bool IsLooping { get; set; } = false;
- [EditorBrowsable(EditorBrowsableState.Never)]
- public int LoopCount { get; set; } = 1;
+ Child = 3
}
}
*
*/
-using System.ComponentModel;
-
namespace Tizen.AIAvatar
{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public interface IAnimationModuleData
+ internal class TrackingController
{
- }
+ internal TrackingController()
+ {
+ }
- [EditorBrowsable(EditorBrowsableState.Never)]
- public enum MotionDataType
- {
- [EditorBrowsable(EditorBrowsableState.Never)]
- AnimationInfo,
- [EditorBrowsable(EditorBrowsableState.Never)]
- MotionData
+ internal void Initialize(TrackingOptions options)
+ {
+ }
+
+ internal void StartMotionTracking()
+ {
+
+ }
+
+ internal void StopMotionTracking()
+ {
+
+ }
}
}
/*
- * Copyright(c) 2023 Samsung Electronics Co., Ltd.
+ * 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.
namespace Tizen.AIAvatar
{
- internal struct UtteranceText
+ internal class TrackingOptions
{
- internal string Text;
- internal int UttID;
}
}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.Collections.Generic;
-using System.ComponentModel;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- internal class BlendShapeInfo
- {
- internal BlendShapeModelInfo blendShape;
- internal BlendShapeVisemeInfo[] visemes;
-
- internal BlendShapeInfo() { }
-
- internal string[] GetNodeNames()
- {
- if (blendShape == null)
- {
- Log.Error(LogTag, "blendShape is null");
- return null;
- }
- return blendShape.nodeNames;
- }
-
- internal int[] GetBlendShapeCounts()
- {
- return blendShape.blendShapeCount;
- }
-
- internal Dictionary<Viseme, BlendShapeValue[]> GetVisemeMap()
- {
- Dictionary<Viseme, BlendShapeValue[]> visemeMap = new Dictionary<Viseme, BlendShapeValue[]>();
-
- foreach (var visemeInfo in visemes)
- {
- visemeMap.Add(visemeInfo.name, visemeInfo.values);
- }
-
- return visemeMap;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
- internal class BlendShapeModelInfo
- {
- internal string keyFormat;
- internal string[] nodeNames;
- internal int[] blendShapeCount;
-
- internal BlendShapeModelInfo(string keyFormat, string[] nodeNames, int[] blendShapeCount)
- {
- this.keyFormat = keyFormat;
- this.nodeNames = nodeNames;
- this.blendShapeCount = blendShapeCount;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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 Tizen.NUI;
-
-namespace Tizen.AIAvatar
-{
- internal class LipInfo
- {
- private Animatable animatable;
- private string nodeName;
- private int blendShapeCount;
-
- internal Animatable Animatable { get => animatable; set => animatable = value; }
- internal string NodeName { get => nodeName; set => nodeName = value; }
- internal int BlendShapeCount { get => blendShapeCount; set => blendShapeCount = value; }
- }
-}
+++ /dev/null
-
-using System.ComponentModel;
-
-namespace Tizen.AIAvatar
-{
- internal interface ISingleShotModel
- {
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void SetTensorData(int index, byte[] buffer);
- [EditorBrowsable(EditorBrowsableState.Never)]
- public byte[] GetTensorData(int index);
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Invoke();
- }
-}
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Tizen.AIAvatar
-{
- internal static class SoftmaxLinqExtension
- {
- internal static IEnumerable<float> SoftMax(this IEnumerable<float> source)
- {
- var exp = source.Select(x => MathF.Exp(x)).ToArray();
- var sum = exp.Sum();
- return exp.Select(x => x / sum);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.
- *
- */
-
-namespace Tizen.AIAvatar
-{
- // Various visemes
- internal enum Viseme
- {
- sil,
- AE,
- Ah,
- B_M_P,
- Ch_J,
- EE,
- Er,
- IH,
- Oh,
- W_OO,
- R,
- };
-}
+++ /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;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract class AnimationModule
- {
- private AvatarMotionState currentMotionState = AvatarMotionState.Unavailable;
-
- private readonly Object motionChangedLock = new Object();
- private event EventHandler<AvatarMotionChangedEventArgs> motionChanged;
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AnimationModule()
- {
-
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarMotionState CurrentMotionState
- {
- get
- {
- return currentMotionState;
- }
- set
- {
- if (currentMotionState == value)
- {
- return;
- }
- var preState = currentMotionState;
- currentMotionState = value;
- if (motionChanged != null)
- {
- motionChanged?.Invoke(this, new AvatarMotionChangedEventArgs(preState, currentMotionState));
- }
- }
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract void Init(Animation animation);
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract void Play(IAnimationModuleData data);
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract void Stop();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract void Pause();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract void Destroy();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- protected void SetCurrentState(AvatarMotionState state)
- {
- CurrentMotionState = state;
- }
-
-
- /// <summary>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public event EventHandler<AvatarMotionChangedEventArgs> MotionStateChanged
- {
- add
- {
- lock (motionChangedLock)
- {
- motionChanged += value;
- }
-
- }
-
- remove
- {
- lock (motionChangedLock)
- {
- if (motionChanged == null)
- {
- Log.Error(LogTag, "Remove StateChanged Failed : motionChanged is null");
- return;
- }
- motionChanged -= value;
- }
- }
- }
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public enum AnimationModuleType
- {
- [EditorBrowsable(EditorBrowsableState.Never)]
- EyeBlinker,
- [EditorBrowsable(EditorBrowsableState.Never)]
- LipSyncer,
- [EditorBrowsable(EditorBrowsableState.Never)]
- MotionBehavior,
- [EditorBrowsable(EditorBrowsableState.Never)]
- JointTransformer,
- }
-}
+++ /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 Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
- internal class AvatarMotions
- {
- private MotionData eyeMotionData;
- private const int blinkDuration = 200;
-
- internal AvatarMotions(AvatarProperties properties)
- {
- CreateEyeBlinkMotionData(properties);
- }
-
- internal MotionData EyeMotionData { get { return eyeMotionData; } }
-
- private void CreateEyeBlinkMotionData(AvatarProperties avatarProperties)
- {
- var keyFrames = new KeyFrames();
- keyFrames.Add(0.1f, 0.0f);
- keyFrames.Add(0.5f, 1.0f);
- keyFrames.Add(0.9f, 0.0f);
-
- var headBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
- var headBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.HeadGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
- var eyelashBlendShapeEyeLeft = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkLeft);
- var eyelashBlendShapeEyeRight = new AvatarBlendShapeIndex(avatarProperties.NodeMapper, NodeType.EyelashGeo, avatarProperties.BlendShapeMapper, BlendShapeType.EyeBlinkRight);
-
- eyeMotionData = new MotionData(blinkDuration);
- if (headBlendShapeEyeLeft != null)
- {
- eyeMotionData.Add(headBlendShapeEyeLeft, new MotionValue(keyFrames));
- }
- if (headBlendShapeEyeRight != null)
- {
- eyeMotionData.Add(headBlendShapeEyeRight, new MotionValue(keyFrames));
- }
- if (eyelashBlendShapeEyeLeft != null)
- {
- eyeMotionData.Add(eyelashBlendShapeEyeLeft, new MotionValue(keyFrames));
- }
- if (eyelashBlendShapeEyeRight != null)
- {
- eyeMotionData.Add(eyelashBlendShapeEyeRight, new MotionValue(keyFrames));
- }
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.Collections.Generic;
-using System.ComponentModel;
-using System.Reflection;
-using Tizen.NUI.Scene3D;
-using Tizen.NUI;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- internal class BlendShapePlayer
- {
- private Dictionary<AnimationModuleType, AnimationModule> animationModules = new Dictionary<AnimationModuleType, AnimationModule>();
-
- private EyeBlinker blinker;
- private AsyncLipSyncer lipSyncer;
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public BlendShapePlayer()
- {
- blinker = new EyeBlinker();
- lipSyncer = new AsyncLipSyncer();
-
- animationModules.Add(AnimationModuleType.EyeBlinker, blinker);
- animationModules.Add(AnimationModuleType.LipSyncer, lipSyncer);
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AsyncLipSyncer LipSyncer => lipSyncer;
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void SetBlinkAnimation(Animation blinkerAnimation)
- {
- animationModules[AnimationModuleType.EyeBlinker].Init(blinkerAnimation);
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void SetLipSyncAnimation(Animation lipsyncAnimation)
- {
- animationModules[AnimationModuleType.LipSyncer].Init(lipsyncAnimation);
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AnimationModule GetAnimationModule(AnimationModuleType type)
- {
- return animationModules[type];
- }
-
- /// <summary>
- /// Start eye blink animation
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void StartEyeBlink()
- {
- animationModules[AnimationModuleType.EyeBlinker]?.Play(null);
- }
-
- /// <summary>
- /// Stop eye blink animation
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void StopEyeBlink()
- {
- animationModules[AnimationModuleType.EyeBlinker]?.Stop();
- }
-
- /// <summary>
- /// Play synchronization avatar lip based on the voice file(byte[])
- /// </summary>
- /// <param name="audio">byte array of voice</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void PlayLipSync(byte[] audio)
- {
- if (animationModules[AnimationModuleType.LipSyncer] == null)
- {
- Log.Error(LogTag, $"error : avatarLipSync is null");
- return;
- }
- var lipData = new LipSyncData();
-
- lipData.AudioFile = new byte[audio.Length];
- Buffer.BlockCopy(audio, 0, lipData.AudioFile, 0, audio.Length);
- animationModules[AnimationModuleType.LipSyncer].Play(lipData);
- }
-
- /// <summary>
- /// Play synchronization avatar lip based on the voice file(byte[])
- /// </summary>
- /// <param name="audio">byte array of voice</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void PlayLipSync(byte[] audio, int sampleRate)
- {
- if (animationModules[AnimationModuleType.LipSyncer] == null)
- {
- Log.Error(LogTag, $"error : avatarLipSync is null");
- return;
- }
- var lipData = new LipSyncData();
-
- lipData.AudioFile = new byte[audio.Length];
- Buffer.BlockCopy(audio, 0, lipData.AudioFile, 0, audio.Length);
- lipData.SampleRate = sampleRate;
- animationModules[AnimationModuleType.LipSyncer].Play(lipData);
- }
-
- /// <summary>
- /// Pause lip synchronization
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void PauseLipSync()
- {
- if (animationModules[AnimationModuleType.LipSyncer] == null)
- {
- Log.Error(LogTag, $"error : avatarLipSync is null");
- return;
- }
- animationModules[AnimationModuleType.LipSyncer].Pause();
- }
-
- /// <summary>
- /// Stop lip synchronization
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void StopLipSync()
- {
- if (animationModules[AnimationModuleType.LipSyncer] == null)
- {
- Log.Error(LogTag, $"error : avatarLipSync is null");
- return;
- }
- animationModules[AnimationModuleType.LipSyncer].Stop();
- }
-
- internal void DestroyAnimations()
- {
- foreach ( var animationModule in animationModules.Values )
- {
- animationModule.Destroy();
- }
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.ComponentModel;
-using Tizen.NUI;
-using Tizen.NUI.Scene3D;
-
-namespace Tizen.AIAvatar
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class JointTransformer
- {
- [EditorBrowsable(EditorBrowsableState.Never)]
- public JointTransformer()
- {
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Init(Animation animation)
- {
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Play(IAnimationModuleData data)
- {
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Pause()
- {
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Stop()
- {
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public void Destroy()
- {
- }
-
- private void SetJointMotion(AvatarProperties properties, JointType jointType, MotionTransformIndex.TransformTypes type, Rotation rotation)
- {
- var motionTransform = new AvatarJointTransformIndex(properties.JointMapper, jointType, type);
- var motionData = new MotionData();
- motionData.Add(
- motionTransform,
- new MotionValue()
- {
- //TODO : Tizen_7.0에 pitch, yaw, roll patch 추가하기
- //PropertyValue = new PropertyValue(new Rotation(new Radian(pitch), new Radian(yaw), new Radian(roll))),
- }
- );
- //avatar.SetMotionData(motionData);
- }
-
- private void SetJointMotion(string keyValue, float pitch, float yaw, float roll)
- {
- var motionData = new MotionData();
- motionData.Add(
- new MotionTransformIndex()
- {
- ModelNodeId = new PropertyKey(keyValue),
- TransformType = MotionTransformIndex.TransformTypes.Orientation,
- },
- new MotionValue()
- {
- //TODO : Tizen_7.0에 pitch, yaw, roll patch 추가하기
- //PropertyValue = new PropertyValue(new Rotation(new Radian(pitch), new Radian(yaw), new Radian(roll))),
- }
- );
- //avatar.SetMotionData(motionData);
- }
-
- private void SetJointMotion(string keyValue, MotionTransformIndex.TransformTypes type, Rotation rotation)
- {
- var motionData = new MotionData();
- motionData.Add(
- new MotionTransformIndex()
- {
- ModelNodeId = new PropertyKey(keyValue),
- TransformType = type,
- },
- new MotionValue()
- {
- PropertyValue = new PropertyValue(rotation),
- }
- );
- //avatar.SetMotionData(motionData);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.ComponentModel;
-using Tizen.NUI.Scene3D;
-using Tizen.NUI;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- /// <summary>
- /// Avatar is a Class to show 3D avatar objects.
- /// It is subclass of Model s.t. we can control Avatar like models animation easly.
- /// For example,
- ///
- /// Avatar supports AR Emoji.
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public class Avatar : Model
- {
- private AvatarProperties avatarProperties = new DefaultAvatarProperties();
- private AvatarMotions avatarMotions;
-
- private BlendShapePlayer avatarAnimator;
- private MotionPlayer motionPlayer;
- private JointTransformer jointTransformer;
-
- /// <summary>
- /// Create an initialized AvatarModel.
- /// </summary>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
- [EditorBrowsable(EditorBrowsableState.Never)]
- public Avatar() : base()
- {
- InitAvatar();
- }
-
- /// <summary>
- /// Create an initialized AREmojiDefaultAvatar.
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public Avatar(AvatarInfo avatarInfo) : base(avatarInfo.ResourcePath)
- {
- InitAvatar();
- }
-
- /// <summary>
- /// Create an initialized Avatar.
- /// </summary>
- /// <param name="avatarlUrl">avatar file url.(e.g. glTF, and DLI).</param>
- /// <param name="resourceDirectoryUrl"> The url to derectory containing resources: binary, image etc.</param>
- /// <remarks>
- /// If resourceDirectoryUrl is empty, the parent directory url of avatarUrl is used for resource url.
- ///
- /// http://tizen.org/privilege/mediastorage for local files in media storage.
- /// http://tizen.org/privilege/externalstorage for local files in external storage.
- /// </remarks>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
- [EditorBrowsable(EditorBrowsableState.Never)]
- public Avatar(string avatarUrl, string resourceDirectoryUrl = "") : base(avatarUrl, resourceDirectoryUrl)
- {
- InitAvatar();
- }
-
- /// <summary>
- /// Copy constructor.
- /// </summary>
- /// <param name="avatar">Source object to copy.</param>
- // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API)
- [EditorBrowsable(EditorBrowsableState.Never)]
- public Avatar(Avatar avatar) : base(avatar)
- {
- InitAvatar();
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarProperties AvatarProperties
- {
- get => avatarProperties;
- set => avatarProperties = value;
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal BlendShapePlayer AvatarAnimator
- {
- get => avatarAnimator;
- set => avatarAnimator = value;
- }
-
-
- /// <summary>
- /// Play avatar animation by AnimationInfo
- /// </summary>
- /// <param name="index">index of default avatar animations</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- private void PlayAnimation(AnimationInfo animationInfo, int duration = 3000, bool isLooping = false, int loopCount = 1)
- {
- if (animationInfo == null)
- {
- Tizen.Log.Error(LogTag, "animationInfo is null");
- return;
- }
- if (animationInfo.MotionData == null)
- {
- Tizen.Log.Error(LogTag, "animationInfo.MotionData is null");
- return;
- }
- var motionAnimation = GenerateMotionDataAnimation(animationInfo.MotionData);
- if (motionAnimation != null)
- {
- motionAnimation.Duration = duration;
- motionAnimation.Looping = isLooping;
- motionAnimation.LoopCount = loopCount;
- motionAnimation.BlendPoint = 0.2f;
- motionPlayer.PlayAnimation(motionAnimation);
- }
- else
- {
- Tizen.Log.Error(LogTag, "motionAnimation is null");
- }
- }
-
- /// <summary>
- /// Play avatar animation by MotionData
- /// </summary>
- /// <param name="index">index of default avatar animations</param>
- [EditorBrowsable(EditorBrowsableState.Never)]
- private void PlayAnimation(MotionData motionData, int duration = 3000, bool isLooping = false, int loopCount = 1)
- {
-
- if (motionData == null)
- {
- Tizen.Log.Error(LogTag, "motionData is null");
- return;
- }
- var motionAnimation = GenerateMotionDataAnimation(motionData);
- if (motionAnimation != null)
- {
- motionAnimation.Duration = duration;
- motionAnimation.Looping = isLooping;
- motionAnimation.LoopCount = loopCount;
- motionAnimation.BlendPoint = 0.2f;
- motionPlayer.PlayAnimation(motionAnimation);
- }
- else
- {
- Tizen.Log.Error(LogTag, "motionAnimation is null");
- }
- }
-
- private void PlayAnimation(int index, int duration = 3000, bool isLooping = false, int loopCount = 1)
- {
- //TODO by index
- //var motionAnimation = GenerateMotionDataAnimation(animationInfoList[index].MotionData);
- /*motionAnimation.Duration = duration;
- motionAnimation.Looping = isLooping;
- motionAnimation.LoopCount = loopCount;
- motionAnimation.BlendPoint = 0.2f;
-
- motionPlayer.PlayAnimation(motionAnimation);*/
- }
-
- /// <summary>
- /// Pause avatar animation
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- private void PauseMotionAnimation()
- {
- motionPlayer.PauseMotionAnimation();
- }
-
- /// <summary>
- /// Stop avatar animation
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- private void StopMotionAnimation()
- {
- motionPlayer?.StopMotionAnimation();
- }
-
-
- private void InitAvatar()
- {
- avatarMotions = new AvatarMotions(avatarProperties);
-
- AvatarAnimator = new BlendShapePlayer();
-
- avatarProperties.AvatarPropertiesChanged += (s, e) =>
- {
- var eyeAnimation = CreateMotionAnimation(avatarMotions.EyeMotionData);
- if (eyeAnimation != null)
- {
- avatarAnimator.SetBlinkAnimation(eyeAnimation);
- }
- };
-
- ResourcesLoaded += (s, e) =>
- {
- var eyeAnimation = CreateMotionAnimation(avatarMotions.EyeMotionData);
- if (eyeAnimation != null)
- {
- avatarAnimator.SetBlinkAnimation(eyeAnimation);
- }
- };
- }
-
- private Animation CreateMotionAnimation(MotionData data)
- {
- return GenerateMotionDataAnimation(data);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.ComponentModel;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class AvatarMic
- {
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal AvatarMic()
- {
- }
-
- /// <summary>
- /// Initialize Microphone for using live lip sync
- /// </summary>
- /// <privilege>http://tizen.org/privilege/recorder</privilege>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool InitAvatarMic(Avatar avatar)
- {
- if (AudioRecorder.Instance == null)
- {
- Log.Error(LogTag, $"Failed to initialize AudioRecorder");
- return false;
- }
- AudioRecorder.Instance?.InitMic(avatar?.AvatarAnimator);
-
- return true;
- }
-
- /// <summary>
- /// Deinitialize Microphone
- /// </summary>
- /// <privilege>http://tizen.org/privilege/recorder</privilege>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool DeinitAvatarMIC()
- {
- AudioRecorder.Instance?.DeinitMic();
-
- return true;
- }
-
- /// <summary>
- /// Start synchronization avatar lip based on the microphone's voice
- /// </summary>
- /// <privilege>http://tizen.org/privilege/recorder</privilege>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void StartMic()
- {
- AudioRecorder.Instance?.StartRecording();
- }
-
- /// <summary>
- /// Stop microphone
- /// </summary>
- /// <privilege>http://tizen.org/privilege/recorder</privilege>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void StopMic()
- {
- AudioRecorder.Instance?.StopRecording();
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.Collections.Generic;
-using System.ComponentModel;
-using System;
-using Tizen.Uix.Tts;
-
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class AvatarTTS
- {
- private TTSLipSyncer ttsLipSyncer;
-
- private event EventHandler ttsReadyFinished;
- private readonly Object ttsReadyFinishedLock = new Object();
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal AvatarTTS()
- {
- }
-
- /// <summary>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal event EventHandler TTSReadyFinished
- {
- add
- {
- lock (ttsReadyFinishedLock)
- {
- ttsReadyFinished += value;
- }
-
- }
-
- remove
- {
- lock (ttsReadyFinishedLock)
- {
- if (ttsReadyFinished == null)
- {
- Log.Error(LogTag, "ttsReadyFinished is null");
- return;
- }
- ttsReadyFinished -= value;
- }
- }
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal TtsClient CurrentTTSClient => ttsLipSyncer?.TtsHandle;
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void InitTTS(Avatar avatar)
- {
- if (ttsLipSyncer == null)
- {
- try
- {
- ttsLipSyncer = new TTSLipSyncer(avatar?.AvatarAnimator?.LipSyncer);
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- }
- }
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void DeinitTTS()
- {
- if (ttsLipSyncer != null)
- {
- try
- {
- ttsLipSyncer.DeinitTts();
- ttsLipSyncer = null;
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- }
- }
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal List<VoiceInfo> GetSupportedVoices()
- {
- return ttsLipSyncer.GetSupportedVoices();
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PrepareTTS(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
-
- if (!ttsLipSyncer.IsSupportedVoice(voiceInfo))
- {
- Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is not supported");
- return false;
- }
-
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
- {
- Log.Info(LogTag, "TTS is not ready");
- return false;
- }
-
- try
- {
- ttsLipSyncer.AddText(text, voiceInfo);
- ttsLipSyncer.Prepare(ttsReadyFinishedCallback);
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PrepareTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
- if (!ttsLipSyncer.IsSupportedVoice(lang))
- {
- Log.Error(LogTag, $"{lang} is not supported");
- return false;
- }
-
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
- {
- Log.Error(LogTag, "TTS is not ready");
- return false;
- }
- try
- {
- ttsLipSyncer.AddText(text, lang);
- ttsLipSyncer.Prepare(ttsReadyFinishedCallback);
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PlayPreparedTTS()
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
- return ttsLipSyncer.PlayPreparedText();
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PlayTTS(string text, VoiceInfo voiceInfo)
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
-
- if (!ttsLipSyncer.IsSupportedVoice(voiceInfo))
- {
- Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is not supported");
- return false;
- }
-
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
- {
- Log.Info(LogTag, "TTS is not ready");
- return false;
- }
-
- try
- {
- ttsLipSyncer.AddText(text, voiceInfo);
- ttsLipSyncer.Play();
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PlayTTS(string text, string lang = "ko_KR")
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
- if (!ttsLipSyncer.IsSupportedVoice(lang))
- {
- Log.Error(LogTag, $"{lang} is not supported");
- return false;
- }
-
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
- {
- Log.Error(LogTag, "TTS is not ready");
- return false;
- }
- try
- {
- ttsLipSyncer.AddText(text, lang);
- ttsLipSyncer.Play();
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PlayTTSAsync(string text, VoiceInfo voiceInfo, EventHandler ttsReadyFinishedCallback = null)
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
-
- if (!ttsLipSyncer.IsSupportedVoice(voiceInfo))
- {
- Log.Info(LogTag, $"{voiceInfo.Lang} & {voiceInfo.Type} is not supported");
- return false;
- }
-
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
- {
- Log.Info(LogTag, "TTS is not ready");
- return false;
- }
-
- try
- {
- ttsLipSyncer.AddText(text, voiceInfo);
- ttsLipSyncer.PlayAsync(ttsReadyFinishedCallback);
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal bool PlayTTS(string text, string lang = "ko_KR", EventHandler ttsReadyFinishedCallback = null)
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return false;
- }
-
- if (!ttsLipSyncer.IsSupportedVoice(lang))
- {
- Log.Error(LogTag, $"{lang} is not supported");
- return false;
- }
-
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- if (ttsLipSyncer.TtsHandle.CurrentState != Tizen.Uix.Tts.State.Ready)
- {
- Log.Error(LogTag, "TTS is not ready");
- return false;
- }
- try
- {
- ttsLipSyncer.AddText(text, lang);
- ttsLipSyncer.PlayAsync(ttsReadyFinishedCallback);
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void PauseTTS()
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return;
- }
-
- try
- {
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- ttsLipSyncer?.Pause();
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- }
- }
-
- /// <summary>
- /// <param name=""></param>
- /// </summary>
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal void StopTTS()
- {
- if (ttsLipSyncer == null || ttsLipSyncer.TtsHandle == null)
- {
- Log.Error(LogTag, "tts is null");
- return;
- }
-
- try
- {
- Log.Info(LogTag, "Current TTS State :" + ttsLipSyncer.TtsHandle.CurrentState);
- ttsLipSyncer?.Stop();
- }
- catch (Exception e)
- {
- Log.Error(LogTag, $"error :{e.Message}");
- Log.Error(LogTag, $"{e.StackTrace}");
- }
- }
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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;
-using static Tizen.AIAvatar.AIAvatar;
-
-namespace Tizen.AIAvatar
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public class AvatarInfo
- {
- [EditorBrowsable(EditorBrowsableState.Never)]
- public string Name { get; private set; }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public string ThumbnailPath { get; private set; }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal string ResourcePath { get; private set; }
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal AvatarInfoOption avatarInfoOption { get; private set; }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarInfo(string path, string Name, AvatarInfoOption info = AvatarInfoOption.Thumbnail)
- {
- this.Name = Name;
- this.avatarInfoOption = info;
-
- if (info == AvatarInfoOption.Thumbnail)
- {
- ThumbnailPath = path;
- }
- else
- {
- ResourcePath = path;
- }
- }
-
- internal AvatarInfo(string directoryPath)
- {
- string path = ApplicationResourcePath + EmojiAvatarResourcePath;
- Name = directoryPath.Substring(path.Length, directoryPath.Length - path.Length);
- ResourcePath = $"{directoryPath}/{AIAvatar.ExternalModel}";
- }
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public enum AvatarInfoOption
- {
- [EditorBrowsable(EditorBrowsableState.Never)]
- Thumbnail = 0,
- [EditorBrowsable(EditorBrowsableState.Never)]
- Resource = 1,
- }
-}
+++ /dev/null
-/*
- * Copyright(c) 2023 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.AIAvatar
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- public class AvatarProperties
- {
- private AvatarPropertyMapper jointMapper;
- private AvatarPropertyMapper blendShapeMapper;
- private AvatarPropertyMapper nodeMapper;
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarProperties(AvatarPropertyMapper jointMapper, AvatarPropertyMapper blendShapeMapper, AvatarPropertyMapper nodeMapper)
- {
- JointMapper = new AvatarPropertyMapper(jointMapper);
- BlendShapeMapper = new AvatarPropertyMapper(blendShapeMapper);
- NodeMapper = new AvatarPropertyMapper(nodeMapper);
- }
-
- internal event EventHandler<AvatarProperties> AvatarPropertiesChanged;
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarPropertyMapper JointMapper
- {
- get
- {
- return jointMapper;
- }
- set
- {
- jointMapper = value;
- AvatarPropertiesChanged?.Invoke(jointMapper, this);
- }
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarPropertyMapper BlendShapeMapper
- {
- get
- {
- return blendShapeMapper;
- }
- set
- {
- blendShapeMapper = value;
- AvatarPropertiesChanged?.Invoke(blendShapeMapper, this);
- }
- }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- public AvatarPropertyMapper NodeMapper
- {
- get
- {
- return nodeMapper;
- }
- set
- {
- nodeMapper = value;
- AvatarPropertiesChanged?.Invoke(nodeMapper, this);
- }
- }
- }
-}
--- /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.
+ *
+ */
+
+namespace Tizen.AIAvatar
+{
+ internal class Test
+ {
+ public void CreateTest()
+ {
+ var avatar1 = new Avatar();
+
+ var avatarInfo = new AvatarInfo("avatarName", "resourcePath");
+ var avatar2 = new Avatar(avatarInfo);
+
+ var avatar3 = new Avatar("resourcePath");
+
+ var avatar4 = new Avatar(avatar1);
+
+ avatar1.Dispose();
+ avatar2.Dispose();
+ avatar3.Dispose();
+ avatar4.Dispose();
+ }
+ }
+}
ProcessorController.Instance.Initialize();
Tizen.Tracer.End();
-#if REMOVE_READONLY_FOR_BINDABLE_PROPERTY
- if(NUIApplication.IsUsingXaml)
- {
- Tizen.NUI.BaseComponents.View.CreateBindableProperties();
- }
-#endif
Log.Info("NUI", "[NUI] OnApplicationInit: GetWindow");
Tizen.Tracer.Begin("[NUI] OnApplicationInit: GetWindow");
- Window.Instance = GetWindow();
+ Window.Instance = Window.Default = GetWindow();
#if !PROFILE_TV
//tv profile never use default focus indicator, so this is not needed!
var target = weakReference.Target;
BaseHandle ret = target as BaseHandle;
- if ((ret == null) || ret.Disposed || ret.IsDisposeQueued)
+ // Note : Do not use ret == null because BaseHandle override operator ==.
+ if ((ret?.Disposed ?? true) || (ret?.IsDisposeQueued ?? true))
{
- // Special case. If WeakReference.Target is null or it might be disposed by GC, just remove previous item forcibly.
- if (Instance._controlMap.TryRemove(refCptr, out weakReference) != true)
- {
- Tizen.Log.Error("NUI", $"Something Wrong when we try to remove null target! input type:{baseHandle.GetType()}, registed type:{target?.GetType()}\n");
- }
+ // Special case. If WeakReference.Target is null or disposed by GC,
+ // Unregister forcibly first. and then try to add again.
+ ret?.UnregisterFromRegistry();
+
if (Instance._controlMap.TryAdd(refCptr, new WeakReference(baseHandle, true)) != true)
{
Tizen.Log.Error("NUI", $"Something Wrong when we try to replace null target! input type:{baseHandle.GetType()}, registed type:{target?.GetType()}\n");
}
}
- NUILog.Debug($"[Registry] Register! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} copyNativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
+ NUILog.Debug($"[Registry] Register! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} refCptr=0x{refCptr.ToInt64():X} NativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
return true;
}
Tizen.Log.Error("NUI", $"something wrong when removing refCptr!\n");
}
- NUILog.Debug($"[Registry] Unregister! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} copyNativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
+ NUILog.Debug($"[Registry] Unregister! type:{baseHandle.GetType()} count:{Instance._controlMap.Count} refCptr=0x{refCptr.ToInt64():X} NativeHandle:{baseHandle.GetBaseHandleCPtrHandleRef.Handle.ToString("X8")}");
return;
}
if (refObjectPtr == global::System.IntPtr.Zero)
{
NUILog.Debug("Registry refObjectPtr is NULL! This means bind native object is NULL!");
- //return null;
+ return null;
}
else
{
}
BaseHandle ret = weakReference.Target as BaseHandle;
- if ((ret == null) || ret.Disposed || ret.IsDisposeQueued)
+ // Note : Do not use ret == null because BaseHandle override operator ==.
+ if ((ret?.Disposed ?? true) || (ret?.IsDisposeQueued ?? true))
{
- // Special case. If WeakReference.Target is null or disposed by GC, just return null.
+ // Special case. If WeakReference.Target is null or disposed by GC,
+ // Unregister first. and then return null.
+ ret?.UnregisterFromRegistry();
return null;
}
return ret;
--- /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.Text;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// VisualObjectsContainer is a container for visual objects.
+ /// For each VisualObjectContainer, there is a corresponding view.
+ /// Each view can have only one VisualObjectsContainer per rangeType.
+ /// </summary>
+ /// <remarks>
+ /// To avoid the collision between Dali toolkit logic and NUI specific policy,
+ /// this container has an internal limitation of the number of visual objects.
+ /// If user try to add visual object over the limitation, it will be ignored.
+ /// </remarks>
+ internal class VisualObjectsContainer : BaseHandle
+ {
+ private List<Tizen.NUI.Visuals.VisualBase> visuals = new List<Tizen.NUI.Visuals.VisualBase>(); // Keep visual object reference.
+
+ /// <summary>
+ /// Creates an empty visual object handle.
+ /// </summary>
+ public VisualObjectsContainer() : this(Interop.VisualObjectsContainer.NewVisualObjectsContainer(), true, false)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Creates an visual object with VisualObjectsContainer.
+ /// </summary>
+ public VisualObjectsContainer(Tizen.NUI.BaseComponents.View view, int rangeType) : this(Interop.VisualObjectsContainer.VisualObjectsContainerNew(Tizen.NUI.BaseComponents.View.getCPtr(view), rangeType), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal VisualObjectsContainer(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal VisualObjectsContainer(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ }
+
+ public Tizen.NUI.BaseComponents.View GetView()
+ {
+ global::System.IntPtr cPtr = Interop.VisualObjectsContainer.GetOwner(SwigCPtr);
+
+ Tizen.NUI.BaseComponents.View ret = null;
+ if (Interop.RefObject.GetRefObjectPtr(cPtr) == global::System.IntPtr.Zero)
+ {
+ // Visual container don't have owner. Return null.
+ Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+ }
+ else
+ {
+ ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Tizen.NUI.BaseComponents.View;
+ if (ret != null)
+ {
+ Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+ }
+ else
+ {
+ ret = new Tizen.NUI.BaseComponents.View(cPtr, true);
+ }
+ }
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ return ret;
+ }
+
+ public int GetContainerRangeType()
+ {
+ return Interop.VisualObjectsContainer.GetContainerRangeType(SwigCPtr);
+ }
+
+ public Tizen.NUI.Visuals.VisualBase this[uint index]
+ {
+ get
+ {
+ return GetVisualObjectAt(index);
+ }
+ }
+
+ public uint GetVisualObjectsCount()
+ {
+ uint ret = Interop.VisualObjectsContainer.GetVisualObjectsCount(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ return ret;
+ }
+
+ public bool AddVisualObject(Tizen.NUI.Visuals.VisualBase visualObject)
+ {
+ // Detach from previous container first.
+ var previousContainer = visualObject.GetVisualContainer();
+ if (previousContainer != null)
+ {
+ if (previousContainer == this)
+ {
+ // Already added to this container.
+ return false;
+ }
+ visualObject.Detach();
+ }
+
+ visuals.Add(visualObject);
+
+ bool ret = Interop.VisualObjectsContainer.AddVisualObject(SwigCPtr, Tizen.NUI.Visuals.VisualBase.getCPtr(visualObject));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ return ret;
+ }
+
+ public void RemoveVisualObject(Tizen.NUI.Visuals.VisualBase visualObject)
+ {
+ visuals.Remove(visualObject);
+
+ Interop.VisualObjectsContainer.RemoveVisualObject(SwigCPtr, Tizen.NUI.Visuals.VisualBase.getCPtr(visualObject));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ public Tizen.NUI.Visuals.VisualBase FindVisualObjectByName(string name)
+ {
+ Tizen.NUI.Visuals.VisualBase ret = null;
+ if(!string.IsNullOrEmpty(name))
+ {
+ foreach (var visual in visuals)
+ {
+ if (visual?.Name == name)
+ {
+ return visual;
+ }
+ }
+ }
+ return ret;
+ }
+
+ private Tizen.NUI.Visuals.VisualBase GetVisualObjectAt(uint index)
+ {
+ global::System.IntPtr cPtr = Interop.VisualObjectsContainer.GetVisualObjectAt(SwigCPtr, index);
+ Visuals.VisualBase ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Visuals.VisualBase;
+ if (ret != null)
+ {
+ Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+ }
+ else
+ {
+ ret = new Visuals.VisualBase(cPtr, true);
+ }
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ return ret;
+ }
+
+ /// <summary>
+ /// Dispose for VisualObjectsContainer
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void Dispose(DisposeTypes type)
+ {
+ if (disposed)
+ {
+ return;
+ }
+
+ if (type == DisposeTypes.Explicit)
+ {
+ //Called by User
+ //Release your own managed resources here.
+ //You should release all of your own disposable objects here.
+ }
+
+ base.Dispose(type);
+ }
+ }
+}
\ No newline at end of file
[global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_InputMethodContext_SetInputPanelPosition")]
public static extern void SetInputPanelPosition(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2, uint jarg3);
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_InputMethodContext_SetInputPanelPositionAlign")]
+ [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+ public static extern bool SetInputPanelPositionAlign(global::System.Runtime.InteropServices.HandleRef inputMethodContext, int x, int y, int align);
+
[global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_InputMethodContext_ActivatedSignal")]
public static extern global::System.IntPtr ActivatedSignal(global::System.Runtime.InteropServices.HandleRef jarg1);
--- /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.
+ *
+ */
+
+namespace Tizen.NUI
+{
+ internal static partial class Interop
+ {
+ internal static partial class VisualObject
+ {
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_New")]
+ public static extern global::System.IntPtr VisualObjectNew();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_GetContainer")]
+ public static extern global::System.IntPtr GetContainer(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_CreateVisual")]
+ public static extern void CreateVisual(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef propertyMap);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_RetrieveVisualPropertyMap")]
+ public static extern void RetrieveVisualPropertyMap(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef propertyMap);
+
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DoAction_UpdatePropertyMap")]
+ public static extern void UpdateVisualPropertyMap(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef propertyMap);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DoActionWithEmptyAttributes")]
+ public static extern void DoActionWithEmptyAttributes(global::System.Runtime.InteropServices.HandleRef visualObject, int actionId);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DoActionWithSingleIntAttributes")]
+ public static extern void DoActionWithSingleIntAttributes(global::System.Runtime.InteropServices.HandleRef visualObject, int actionId, int actionValue);
+
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_SetSiblingOrder")]
+ public static extern void SetSiblingOrder(global::System.Runtime.InteropServices.HandleRef visualObject, uint siblingOrder);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_GetSiblingOrder")]
+ public static extern uint GetSiblingOrder(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_DetachFromContainer")]
+ public static extern void Detach(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_Raise")]
+ public static extern uint Raise(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_Lower")]
+ public static extern uint Lower(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_RaiseToTop")]
+ public static extern uint RaiseToTop(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_LowerToBottom")]
+ public static extern uint LowerToBottom(global::System.Runtime.InteropServices.HandleRef visualObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_RaiseAbove")]
+ public static extern uint RaiseAbove(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef target);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObject_LowerBelow")]
+ public static extern uint LowerBelow(global::System.Runtime.InteropServices.HandleRef visualObject, global::System.Runtime.InteropServices.HandleRef target);
+ }
+ }
+}
--- /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.
+ *
+ */
+
+namespace Tizen.NUI
+{
+ internal static partial class Interop
+ {
+ internal static partial class VisualObjectsContainer
+ {
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeBackgroundEffectGet")]
+ public static extern int ContainerRangeTypeBackgroundEffectGet();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeBackgroundGet")]
+ public static extern int ContainerRangeTypeBackgroundGet();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeContentGet")]
+ public static extern int ContainerRangeTypeContentGet();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeDecorationGet")]
+ public static extern int ContainerRangeTypeDecorationGet();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_ContainerRangeTypeForegroundEffectGet")]
+ public static extern int ContainerRangeTypeForegroundEffectGet();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_new_VisualObjectsContainer__SWIG_0")]
+ public static extern global::System.IntPtr NewVisualObjectsContainer();
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_delete_VisualObjectsContainer")]
+ public static extern void DeleteVisualObjectsContainer(global::System.Runtime.InteropServices.HandleRef container);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_New")]
+ public static extern global::System.IntPtr VisualObjectsContainerNew(global::System.Runtime.InteropServices.HandleRef view, int rangeType);
+
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetOwner")]
+ public static extern global::System.IntPtr GetOwner(global::System.Runtime.InteropServices.HandleRef container);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetContainerRangeType")]
+ public static extern int GetContainerRangeType(global::System.Runtime.InteropServices.HandleRef container);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetVisualObjectsCount")]
+ public static extern uint GetVisualObjectsCount(global::System.Runtime.InteropServices.HandleRef container);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_GetVisualObjectAt")]
+ public static extern global::System.IntPtr GetVisualObjectAt(global::System.Runtime.InteropServices.HandleRef container, uint index);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_AddVisualObject")]
+ [return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.U1)]
+ public static extern bool AddVisualObject(global::System.Runtime.InteropServices.HandleRef container, global::System.Runtime.InteropServices.HandleRef viewObject);
+
+ [global::System.Runtime.InteropServices.DllImport(NDalicPINVOKE.Lib, EntryPoint = "CSharp_Dali_VisualObjectsContainer_RemoveVisualObject")]
+ public static extern void RemoveVisualObject(global::System.Runtime.InteropServices.HandleRef container, global::System.Runtime.InteropServices.HandleRef viewObject);
+ }
+ }
+}
backgroundExtraDataUpdatedFlag &= ~BackgroundExtraDataUpdatedFlag.ContentsCornerRadius;
backgroundExtraDataUpdatedFlag &= ~BackgroundExtraDataUpdatedFlag.ContentsBorderline;
- // Do Fitting Buffer when desired dimension is set
- // TODO : Couldn't we do this job in dali-engine side.
- if (_desired_width != -1 && _desired_height != -1)
- {
- if (!string.IsNullOrEmpty(_resourceUrl))
- {
- Size2D imageSize = ImageLoader.GetOriginalImageSize(_resourceUrl, true);
- if (imageSize.Height > 0 && imageSize.Width > 0 && _desired_width > 0 && _desired_height > 0)
- {
- int adjustedDesiredWidth, adjustedDesiredHeight;
- float aspectOfDesiredSize = (float)_desired_height / (float)_desired_width;
- float aspectOfImageSize = (float)imageSize.Height / (float)imageSize.Width;
- if (aspectOfImageSize > aspectOfDesiredSize)
- {
- adjustedDesiredWidth = _desired_width;
- adjustedDesiredHeight = imageSize.Height * _desired_width / imageSize.Width;
- }
- else
- {
- adjustedDesiredWidth = imageSize.Width * _desired_height / imageSize.Height;
- adjustedDesiredHeight = _desired_height;
- }
-
- PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
- cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
- returnWidth?.Dispose();
- PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
- cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
- returnHeight?.Dispose();
- PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
- cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
- scaleToFit?.Dispose();
- }
- imageSize?.Dispose();
- }
- }
-
UpdateImageMap();
}
static View()
{
-#if REMOVE_READONLY_FOR_BINDABLE_PROPERTY
- //to get "IsUsingXaml" feature working at preload, we need to remove readonly for BindableProperty.
-#else
if (NUIApplication.IsUsingXaml)
{
+#if REMOVE_READONLY_FOR_BINDABLE_PROPERTY
+ CreateBindableProperties();
+#else
StyleNameProperty = BindableProperty.Create(nameof(StyleName), typeof(string), typeof(View), string.Empty,
propertyChanged: SetInternalStyleNameProperty, defaultValueCreator: GetInternalStyleNameProperty);
RegisterPropertyGroup(ScaleXProperty, scalePropertyGroup);
RegisterPropertyGroup(ScaleYProperty, scalePropertyGroup);
RegisterPropertyGroup(ScaleZProperty, scalePropertyGroup);
- }
#endif
+ }
RegisterAccessibilityDelegate();
}
static internal new void Preload()
{
Container.Preload();
-
- // not needed, at preload, APP can not set the "IsUsingXaml" flag, it have the default value at preload
- // if (NUIApplication.IsUsingXaml)
- // {
- // // Do nothing. Just call for load static values.
- // var temporalPositionPropertyGroup = positionPropertyGroup;
- // var temporalSizePropertyGroup = sizePropertyGroup;
- // var temporalScalePropertyGroup = scalePropertyGroup;
- // }
}
/// <summary>
// keep readonly for BindableProperty
#endif
+
/// <summary>
/// Gets View's Size2D set by user.
/// </summary>
internalCurrentScreenPosition?.Dispose();
internalCurrentScreenPosition = null;
+ if (visualContainers != null)
+ {
+ foreach (var visualContainer in visualContainers)
+ {
+ visualContainer?.Dispose();
+ }
+ visualContainers = null;
+ }
+
if (type == DisposeTypes.Explicit)
{
//Called by User
--- /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.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using Tizen.NUI.Binding;
+
+namespace Tizen.NUI.BaseComponents
+{
+ /// <summary>
+ /// View is the base class for all views.
+ /// </summary>
+ /// <since_tizen> 3 </since_tizen>
+ public partial class View
+ {
+ #region Internal and Private
+ private List<Tizen.NUI.Visuals.VisualObjectsContainer> visualContainers = null;
+
+ /// <summary>
+ /// Range of visual for the container.
+ /// </summary>
+ internal struct ContainerRangeType
+ {
+ /// <summary>
+ /// Visual will be rendered under the shadow.
+ /// </summary>
+ internal static readonly int Shadow = Interop.VisualObjectsContainer.ContainerRangeTypeBackgroundEffectGet();
+
+ /// <summary>
+ /// Visual will be rendered under the background.
+ /// </summary>
+ internal static readonly int Background = Interop.VisualObjectsContainer.ContainerRangeTypeBackgroundGet();
+
+ /// <summary>
+ /// Visual will be rendered under the content.
+ /// It is default value.
+ /// </summary>
+ internal static readonly int Content = Interop.VisualObjectsContainer.ContainerRangeTypeContentGet();
+
+ /// <summary>
+ /// Visual will be rendered under the decoration.
+ /// </summary>
+ internal static readonly int Decoration = Interop.VisualObjectsContainer.ContainerRangeTypeDecorationGet();
+
+ /// <summary>
+ /// Visual will be rendered above the foreground effect.
+ /// </summary>
+ internal static readonly int ForegroundEffect = Interop.VisualObjectsContainer.ContainerRangeTypeForegroundEffectGet();
+ };
+ #endregion
+
+ #region Public Methods
+ /// <summary>
+ /// Add a Tizen.NUI.Visuals.VisualBase to the view.
+ /// </summary>
+ /// <remarks>
+ /// The visual is added to the top of the visuals.
+ /// If the container cannot add more than maxium count of visuals
+ /// or the visual is already added, It will be ignored.
+ ///
+ /// If input visual already added to another view,
+ /// visual will be detached from old view and added to this view.
+ /// </remarks>
+ /// <param name="visualBase">The visual to add.</param>
+ /// <returns>True if the visual was added successfully, false otherwise.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool AddVisual(Tizen.NUI.Visuals.VisualBase visualBase)
+ {
+ return AddVisualInternal(visualBase, ContainerRangeType.Content);
+ }
+
+ /// <summary>
+ /// Remove a Tizen.NUI.Visuals.VisualBase from the view.
+ /// </summary>
+ /// <remarks>
+ /// The <see cref="Tizen.NUI.Visuals.VisualBase.SiblingOrder"/> value of all other Visuals.VisualBases will be changed automatically.
+ /// </remarks>
+ /// <param name="visualBase">The visual to remove.</param>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RemoveVisual(Tizen.NUI.Visuals.VisualBase visualBase)
+ {
+ if (visualContainers != null)
+ {
+ foreach (var visualContainer in visualContainers)
+ {
+ visualContainer?.RemoveVisualObject(visualBase);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get a Tizen.NUI.Visuals.VisualBase by sibling index
+ /// </summary>
+ /// <returns>Get visual base by sibling index</returns>
+ /// <exception cref="InvalidOperationException"> Thrown when index is out of bounds. </exception>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.Visuals.VisualBase GetVisualAt(uint index)
+ {
+ return GetVisualAtInternal(index, ContainerRangeType.Content);
+ }
+
+ /// <summary>
+ /// Get total number of Tizen.NUI.Visuals.VisualBase which we added using <see cref="AddVisual"/>.
+ /// </summary>
+ /// <returns>Get the number of visual base.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public uint GetVisualsCount()
+ {
+ return GetVisualsCountInternal(ContainerRangeType.Content);
+ }
+
+ /// <summary>
+ /// Find Tizen.NUI.Visuals.VisualBase by name. Given name should not be empty.
+ /// </summary>
+ /// <returns>Get the visual base.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Visuals.VisualBase FindVisualByName(string name)
+ {
+ Visuals.VisualBase ret = null;
+ if (visualContainers != null)
+ {
+ foreach (var visualContainer in visualContainers)
+ {
+ if (visualContainer != null)
+ {
+ ret = visualContainer.FindVisualObjectByName(name);
+ if (ret != null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+ }
+ #endregion
+
+ #region Internal Method
+ internal bool AddVisualInternal(Tizen.NUI.Visuals.VisualBase visualBase, int rangeType)
+ {
+ var visualContainer = EnsureVisualContainer(rangeType);
+ return visualContainer.AddVisualObject(visualBase);
+ }
+
+ internal Tizen.NUI.Visuals.VisualBase GetVisualAtInternal(uint index, int rangeType)
+ {
+ if (index >= GetVisualsCountInternal(rangeType))
+ {
+ throw new InvalidOperationException($"Index {index} is out of bounds. Bound is {GetVisualsCountInternal(rangeType)}");
+ }
+ var visualContainer = EnsureVisualContainer(rangeType);
+ return visualContainer[index];
+ }
+
+ internal uint GetVisualsCountInternal(int rangeType)
+ {
+ uint ret = 0;
+ if (visualContainers != null)
+ {
+ foreach (var visualContainer in visualContainers)
+ {
+ if (visualContainer != null && visualContainer.GetContainerRangeType() == rangeType)
+ {
+ ret = visualContainer.GetVisualObjectsCount();
+ break;
+ }
+ }
+ }
+ return ret;
+ }
+
+ private Tizen.NUI.Visuals.VisualObjectsContainer EnsureVisualContainer(int rangeType)
+ {
+ if (visualContainers == null)
+ {
+ visualContainers = new List<Tizen.NUI.Visuals.VisualObjectsContainer>();
+ }
+
+ foreach (var visualContainer in visualContainers)
+ {
+ if (visualContainer != null && visualContainer.GetContainerRangeType() == rangeType)
+ {
+ return visualContainer;
+ }
+ }
+
+ var newContainer = new Tizen.NUI.Visuals.VisualObjectsContainer(this, rangeType);
+ visualContainers.Add(newContainer);
+ return newContainer;
+ }
+ #endregion
+ }
+}
}
set
{
- using (PropertyKey pKey = new PropertyKey(key))
- {
- SetValue(pKey, value);
- }
+ SetValue(key, value);
}
}
}
set
{
- using (PropertyKey pKey = new PropertyKey(key))
- {
- SetValue(pKey, value);
- }
+ SetValue(key, value);
}
}
}
/// <summary>
+ /// Removes the element by the specified integer key.
+ /// </summary>
+ /// <param name="key">The index key to find.</param>
+ /// <returns>True if the element is removed, false otherwise.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool Remove(int key)
+ {
+ return Interop.PropertyMap.Remove(SwigCPtr, key);
+ }
+
+ /// <summary>
/// Determines whether the PropertyMap contains the specified key.
/// </summary>
/// <param name="key">The index key to find.</param>
{
Interop.PropertyMap.SetValueStringKey(SwigCPtr, key.StringKey, PropertyValue.getCPtr(value));
}
- if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal void SetValue(int key, PropertyValue value)
+ {
+ Interop.PropertyMap.SetValueIntKey(SwigCPtr, key, PropertyValue.getCPtr(value));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal void SetValue(string key, PropertyValue value)
+ {
+ Interop.PropertyMap.SetValueStringKey(SwigCPtr, key, PropertyValue.getCPtr(value));
+ NDalicPINVOKE.ThrowExceptionIfExists();
}
/// This will not be public opened.
DragType type = (DragType)Interop.DragAndDrop.GetAction(dragEvent);
DragEvent ev = new DragEvent();
global::System.IntPtr cPtr = Interop.DragAndDrop.GetPosition(dragEvent);
- ev.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, false);
+ ev.Position = (cPtr == global::System.IntPtr.Zero) ? null : new Position(cPtr, true);
if (type == DragType.Enter)
{
}
/// <summary>
+ /// Enumeration for align of the input panel.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum InputPanelAlign
+ {
+ /// <summary>
+ /// The top-left corner.
+ /// </summary>
+ TopLeft,
+ /// <summary>
+ /// The top-center position.
+ /// </summary>
+ TopCenter,
+ /// <summary>
+ /// The top-right corner.
+ /// </summary>
+ TopRight,
+ /// <summary>
+ /// The middle-left position.
+ /// </summary>
+ MiddleLeft,
+ /// <summary>
+ /// The middle-center position.
+ /// </summary>
+ MiddleCenter,
+ /// <summary>
+ /// The middle-right position.
+ /// </summary>
+ MiddleRight,
+ /// <summary>
+ /// The bottom-left corner.
+ /// </summary>
+ BottomLeft,
+ /// <summary>
+ /// The bottom-center position.
+ /// </summary>
+ BottomCenter,
+ /// <summary>
+ /// The bottom-right corner.
+ /// </summary>
+ BottomRight
+ }
+
+ /// <summary>
/// Gets or sets whether the IM context allows to use the text prediction.
/// </summary>
/// <since_tizen> 8 </since_tizen>
}
/// <summary>
+ /// Sets the alignment and its x,y coordinates of the input panel.<br/>
+ /// Regardless of the rotation degree, the x, y values of the top-left corner on the screen are based on 0, 0.<br/>
+ /// When the IME size is changed, its size will change according to the set alignment.
+ /// </summary>
+ /// <remarks>
+ /// This API can be used to set the alignment of a floating IME.
+ /// </remarks>
+ /// <param name="x">The x coordinate of the InputPanelAlign value.</param>
+ /// <param name="y">The y coordinate of the InputPanelAlign value.</param>
+ /// <param name="align">one of the InputPanelAlign values specifying the desired alignment.</param>
+ /// <returns>True on success, false otherwise.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool SetInputPanelPositionAlign(int x, int y, InputMethodContext.InputPanelAlign align)
+ {
+ bool ret = Interop.InputMethodContext.SetInputPanelPositionAlign(SwigCPtr, x, y, (int)align);
+ if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
+ /// <summary>
/// Sets the language of the input panel.
/// </summary>
/// <param name="language">The language to be set to the input panel</param>
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
FitWidth,
+ /// <summary>
+ /// The visual should not use fitting mode.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ DontCare,
}
/// <summary>
--- /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.
+//
+
+extern alias TizenSystemSettings;
+using TizenSystemSettings.Tizen.System;
+
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// The text visual with advanced options.
+ /// </summary>
+ /// <remarks>
+ /// It will be used when we want to control TextVisual with more options.
+ /// This visual allow to translated text with SID.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class AdvancedTextVisual : Visuals.TextVisual
+ {
+ #region Internal
+ private string textLabelSid = null;
+
+ private static Tizen.NUI.SystemLocaleLanguageChanged systemLocaleLanguageChanged = new Tizen.NUI.SystemLocaleLanguageChanged();
+ private bool hasSystemLanguageChanged = false;
+ #endregion
+
+ #region Constructor
+ public AdvancedTextVisual() : base()
+ {
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// The TranslatableText property.<br />
+ /// The text can set the SID value.<br />
+ /// </summary>
+ /// <exception cref='global::System.ArgumentNullException'>
+ /// ResourceManager about multilingual is null.
+ /// </exception>
+ public string TranslatableText
+ {
+ get
+ {
+ return textLabelSid;
+ }
+ set
+ {
+ if (NUIApplication.MultilingualResourceManager == null)
+ {
+ throw new global::System.ArgumentNullException(null, "ResourceManager about multilingual is null");
+ }
+ string translatableText = null;
+ textLabelSid = value;
+ translatableText = NUIApplication.MultilingualResourceManager?.GetString(textLabelSid, new global::System.Globalization.CultureInfo(SystemSettings.LocaleLanguage.Replace("_", "-")));
+
+ if (translatableText != null)
+ {
+ Text = translatableText;
+ if (hasSystemLanguageChanged == false)
+ {
+ systemLocaleLanguageChanged.Add(SystemSettingsLocaleLanguageChanged);
+ hasSystemLanguageChanged = true;
+ }
+ }
+ else
+ {
+ Text = value;
+ }
+ }
+ }
+ #endregion
+
+ #region Internal Method
+ private void SystemSettingsLocaleLanguageChanged(object sender, LocaleLanguageChangedEventArgs e)
+ {
+ string translatableText = null;
+ translatableText = NUIApplication.MultilingualResourceManager?.GetString(textLabelSid, new global::System.Globalization.CultureInfo(e.Value.Replace("_", "-")));
+ if (translatableText != null)
+ {
+ Text = translatableText;
+ }
+ else
+ {
+ Tizen.Log.Error("NUI", $"Fail to get translated text : {textLabelSid};");
+ Text = textLabelSid;
+ }
+ }
+
+ /// <inheritdoc/>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void Dispose(DisposeTypes type)
+ {
+ if (Disposed)
+ {
+ return;
+ }
+
+ if (hasSystemLanguageChanged)
+ {
+ systemLocaleLanguageChanged.Remove(SystemSettingsLocaleLanguageChanged);
+ }
+
+ base.Dispose(type);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// The visual which can display and control an animated image resource.
+ /// We can also set image sequences by using ResourceUrlList and FrameDelay property.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class AnimatedImageVisual : ImageVisual
+ {
+ #region Internal And Private
+ internal static readonly int ActionPlay = Tizen.NUI.BaseComponents.ImageView.ActionPlay;
+ internal static readonly int ActionPause = Tizen.NUI.BaseComponents.ImageView.ActionPause;
+ internal static readonly int ActionStop = Tizen.NUI.BaseComponents.ImageView.ActionStop;
+
+ internal static readonly int ActionJumpTo = Tizen.NUI.BaseComponents.AnimatedImageView.ActionJumpTo;
+
+ private List<string> resourceUrls = null;
+ #endregion
+
+ #region Constructor
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public AnimatedImageVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal AnimatedImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal AnimatedImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ Type = (int)Tizen.NUI.Visual.Type.AnimatedImage;
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// Gets and Sets the url list in the AnimatedImageVisual.
+ /// </summary>
+ /// <remarks>
+ /// If we set ResourceUrlList as non-null, ImageVisual.ResourceUrl will be ignored.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public List<string> ResourceUrlList
+ {
+ get
+ {
+ return resourceUrls;
+ }
+ set
+ {
+ resourceUrls = value;
+
+ // Always request to create new visual
+ visualCreationRequiredFlag = true;
+ ReqeustProcessorOnceEvent();
+ }
+ }
+
+ /// <summary>
+ /// The number of milliseconds between each frame in the Image-Array animation.
+ /// </summary>
+ /// <remarks>
+ /// This is only used when ResourceUrlList(multiple string) are provided.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int FrameDelay
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.FrameDelay, new PropertyValue(value));
+ }
+ get
+ {
+ int ret = 100;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.FrameDelay);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets and sets the number of times the AnimatedImageVisual will be looped.
+ /// The default is -1. If the number is less than 0 then it loops unlimited,otherwise loop loopCount times.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int LoopCount
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoopCount, new PropertyValue(value));
+ }
+ get
+ {
+ int ret = -1;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoopCount);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Sets or gets the stop behavior.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.BaseComponents.AnimatedImageView.StopBehaviorType StopBehavior
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.StopBehavior, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)Tizen.NUI.BaseComponents.AnimatedImageView.StopBehaviorType.CurrentFrame;
+ var propertyValue = GetVisualProperty((int)Tizen.NUI.ImageVisualProperty.StopBehavior);
+ propertyValue?.Get(out ret);
+ return (Tizen.NUI.BaseComponents.AnimatedImageView.StopBehaviorType)ret;
+ }
+ }
+
+ /// <summary>
+ /// Get the number of total frames.
+ /// Or -1 if image is invalid, or not loaded yet.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int TotalFrame
+ {
+ get
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ int ret = -1;
+ var propertyValue = GetCurrentVisualProperty((int)Tizen.NUI.ImageVisualProperty.TotalFrameNumber);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Set or get the current frame. When setting a specific frame, it is displayed as a still image.
+ /// </summary>
+ /// <remarks>
+ /// Gets the value set by a user. If the setting value is out-ranged, it is reset as a minimum frame or a maximum frame.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int CurrentFrame
+ {
+ set
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ Interop.VisualObject.DoActionWithSingleIntAttributes(SwigCPtr, ActionJumpTo, value);
+ }
+ get
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ int ret = -1;
+ var propertyValue = GetCurrentVisualProperty((int)Tizen.NUI.ImageVisualProperty.CurrentFrameNumber);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets and Sets the batch size for pre-loading images in the AnimatedImageVisual. (Advanced)
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int BatchSize
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.BatchSize, new PropertyValue(value));
+ }
+ get
+ {
+ int ret = 1;
+ var propertyValue = GetVisualProperty((int)Tizen.NUI.ImageVisualProperty.BatchSize);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets and Sets the cache size for loading images in the AnimatedImageVisual. (Advanced)
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int CacheSize
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.CacheSize, new PropertyValue(value));
+ }
+ get
+ {
+ int ret = 1;
+ var propertyValue = GetVisualProperty((int)Tizen.NUI.ImageVisualProperty.CacheSize);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ /// <summary>
+ /// Play the animated image.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Play()
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionPlay);
+ }
+
+ /// <summary>
+ /// Pause the animated image.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Pause()
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionPause);
+ }
+
+ /// <summary>
+ /// Stop the animated image.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Stop()
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionStop);
+ }
+ #endregion
+
+ #region Internal Methods
+ internal override void OnUpdateVisualPropertyMap()
+ {
+ if (resourceUrls != null && resourceUrls.Count > 0)
+ {
+ using var urlArray = new PropertyArray();
+ foreach (var url in resourceUrls)
+ {
+ urlArray.Add(new PropertyValue(url));
+ }
+ using var urlArrayValue = new PropertyValue(urlArray);
+
+ if (cachedVisualPropertyMap != null)
+ {
+ // Remove ResourceUrl from cachedVisualPropertyMap
+ cachedVisualPropertyMap.Remove((int)Tizen.NUI.ImageVisualProperty.URL);
+ cachedVisualPropertyMap.Add((int)Tizen.NUI.ImageVisualProperty.URL, urlArrayValue);
+ }
+ }
+ else
+ {
+ // If we don't use image sequence, follow the ImageVisual logic.
+ base.OnUpdateVisualPropertyMap();
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// Simple visual to render a solid border.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class BorderVisual : VisualBase
+ {
+ #region Constructor
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public BorderVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal BorderVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal BorderVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ Type = (int)Tizen.NUI.Visual.Type.Border;
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// Gets or sets the color of the border.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.Color BorderColor
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.BorderVisualProperty.Color, new PropertyValue(value));
+ }
+ get
+ {
+ Tizen.NUI.Color ret = new Tizen.NUI.Color();
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.BorderVisualProperty.Color);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the width of the border (in pixels).
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float BorderWidth
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.BorderVisualProperty.Size, new PropertyValue(value));
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.BorderVisualProperty.Size);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets whether the anti-aliasing of the border is required. default is false.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool AntiAliasing
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.BorderVisualProperty.AntiAliasing, new PropertyValue(value));
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.BorderVisualProperty.AntiAliasing);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// Simple visual to render a solid color.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class ColorVisual : VisualBase
+ {
+ #region Constructor
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ColorVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal ColorVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal ColorVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ Type = (int)Tizen.NUI.Visual.Type.Color;
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// Blur radius for this visual
+ /// </summary>
+ /// <remarks>
+ /// This property will ignore BorderlineWidth property when we set BlurRadius property at least one time.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float BlurRadius
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ColorVisualProperty.BlurRadius, new PropertyValue(value), false);
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ColorVisualProperty.BlurRadius);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+
+ #region Decorated Visual Properties
+ /// <summary>
+ /// The radius for the rounded corners of the visual.
+ /// The values in Vector4 are used in clockwise order from top-left to bottom-left : Vector4(top-left-corner, top-right-corner, bottom-right-corner, bottom-left-corner).
+ /// Each radius will clamp internally to the half of smaller of the visual's width or height.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Vector4 CornerRadius
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius, new PropertyValue(value), false);
+ }
+ get
+ {
+ Vector4 ret = new Vector4();
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Whether the CornerRadius property value is relative (percentage [0.0f to 0.5f] of the visual size) or absolute (in world units).
+ /// It is absolute by default.
+ /// When the policy is relative, the corner radius is relative to the smaller of the visual's width and height.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType CornerRadiusPolicy
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy, new PropertyValue((int)value), false);
+ }
+ get
+ {
+ int ret = (int)VisualTransformPolicyType.Absolute;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy);
+ propertyValue?.Get(out ret);
+ return (VisualTransformPolicyType)ret;
+ }
+ }
+
+ /// <summary>
+ /// The width for the borderline of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float BorderlineWidth
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth, new PropertyValue(value), false);
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The color for the borderline of the visual.
+ /// It is Color.Black by default.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Color BorderlineColor
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor, new PropertyValue(value), false);
+ }
+ get
+ {
+ Color ret = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The Relative offset for the borderline of the visual.
+ /// Recommended range : [-1.0f to 1.0f].
+ /// If -1.0f, draw borderline inside of the visual.
+ /// If 1.0f, draw borderline outside of the visual.
+ /// If 0.0f, draw borderline half inside and half outside.
+ /// It is 0.0f by default.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float BorderlineOffset
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset, new PropertyValue(value), false);
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// The visual which can display an image resource.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class ImageVisual : VisualBase
+ {
+ #region Internal And Private
+ internal static readonly int ActionReload = Tizen.NUI.BaseComponents.ImageView.ActionReload;
+ internal bool isResourceUrlValid = false;
+
+ private PropertyMap temperalStoredPropertyMap = null; // To store property map when resource url is not valid.
+ #endregion
+
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ImageVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal ImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal ImageVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ Type = (int)Tizen.NUI.Visual.Type.Image;
+ }
+
+ #region Visual Properties
+ /// <summary>
+ /// Gets or sets the URL of the image.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string ResourceUrl
+ {
+ set
+ {
+ if(string.IsNullOrEmpty(value))
+ {
+ isResourceUrlValid = false;
+
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.URL, null);
+
+ // Special behavior. If ResourceUrl is empty, unregister visual, and do not show anything.
+ UnregisterVisual();
+ }
+ else
+ {
+ isResourceUrlValid = true;
+
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.URL, new PropertyValue(value));
+
+ // Special case. If set GeneratedUrl, or FastTrackUploading, Create ImageVisual synchronously.
+ if (value.StartsWith("dali://") || value.StartsWith("enbuf://") || FastTrackUploading)
+ {
+ UpdateVisualPropertyMap();
+ }
+ }
+ }
+ get
+ {
+ string ret = "";
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.URL);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the image area to be displayed.<br />
+ /// It is a rectangular area.<br />
+ /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
+ /// If not specified, the default value is Vector4 (0.0, 0.0, 1.0, 1.0), i.e., the entire area of the image.<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Vector4 PixelArea
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.PixelArea, new PropertyValue(value), false);
+ }
+ get
+ {
+ Vector4 ret = new Vector4(0.0f, 0.0f, 1.0f, 1.0f);
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.PixelArea);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// ImageView PreMultipliedAlpha, type Boolean.<br />
+ /// Image must be initialized.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool PreMultipliedAlpha
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.PremultipliedAlpha, new PropertyValue(value), true);
+ }
+ get
+ {
+ bool ret = true;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.PremultipliedAlpha);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Synchronously load the image for the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool SynchronousLoading
+ {
+ set
+ {
+ // Note : We need to create new visual if previous visual was async, and now we set value as sync.
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.SynchronousLoading, new PropertyValue(value), value);
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.SynchronousLoading);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets whether to automatically correct the orientation of an image.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool OrientationCorrection
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.OrientationCorrection, new PropertyValue(value), true);
+ }
+ get
+ {
+ bool ret = true;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.OrientationCorrection);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the URL of the alpha mask.<br />
+ /// Optional.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string AlphaMaskURL
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.AlphaMaskURL, string.IsNullOrEmpty(value) ? null : new PropertyValue(value));
+ }
+ get
+ {
+ string ret = "";
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.AlphaMaskURL);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets scale factor to apply to the content image before masking.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float MaskContentScale
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskContentScale, new PropertyValue(value));
+ }
+ get
+ {
+ float ret = 1.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskContentScale);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Whether to crop image to mask or scale mask to fit image.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool CropToMask
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.CropToMask, new PropertyValue(value));
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.CropToMask);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets whether to apply mask on GPU or not.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.BaseComponents.ImageView.MaskingModeType MaskingMode
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskingMode, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)Tizen.NUI.BaseComponents.ImageView.MaskingModeType.MaskingOnLoading;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.MaskingMode);
+ propertyValue?.Get(out ret);
+ return (Tizen.NUI.BaseComponents.ImageView.MaskingModeType)ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets whether to apply fast track uploading or not.<br />
+ /// </summary>
+ /// <remarks>
+ /// If we use fast track uploading feature, It can upload texture without event-thead dependency. But also,<br />
+ /// - Texture size is invalid until ResourceReady signal comes.<br />
+ /// - Texture cannot be cached (We always try to load new image).<br />
+ /// - Seamless visual change didn't supported.<br />
+ /// - Alpha masking didn't supported. If you try, It will load as normal case.<br />
+ /// - Synchronous loading didn't supported. If you try, It will load as normal case.<br />
+ /// - Reload action didn't supported. If you try, It will load as normal case.<br />
+ /// - Atlas loading didn't supported. If you try, It will load as normal case.<br />
+ /// - Custom shader didn't supported. If you try, It will load as normal case.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool FastTrackUploading
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.FastTrackUploading, new PropertyValue(value));
+
+ if (value && !string.IsNullOrEmpty(ResourceUrl))
+ {
+ // Special case. If user set FastTrackUploading mean, user want to upload image As-Soon-As-Possible.
+ // Create ImageVisual synchronously.
+ UpdateVisualPropertyMap();
+ }
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.FastTrackUploading);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the Image Visual release policy.<br/>
+ /// It decides if a texture should be released from the cache or kept to reduce the loading time.<br/>
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ReleasePolicyType ReleasePolicy
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.ReleasePolicy, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)ReleasePolicyType.Detached;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.ReleasePolicy);
+ propertyValue?.Get(out ret);
+ return (ReleasePolicyType)ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the desired image width.<br />
+ /// If not specified, the actual image width is used.<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int DesiredWidth
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredWidth, new PropertyValue(value));
+ }
+ get
+ {
+ int ret = -1;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredWidth);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the desired image height.<br />
+ /// If not specified, the actual image height is used.<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int DesiredHeight
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredHeight, new PropertyValue(value));
+ }
+ get
+ {
+ int ret = -1;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.DesiredHeight);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the Image Visual image loading policy.<br />
+ /// It decides if a texture should be loaded immediately after source set or only after the visual is added to the window.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public LoadPolicyType LoadPolicy
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoadPolicy, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)LoadPolicyType.Attached;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.LoadPolicy);
+ propertyValue?.Get(out ret);
+ return (LoadPolicyType)ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the wrap mode for the u coordinate.<br />
+ /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
+ /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
+ /// For normal quad images only.<br />
+ /// Optional.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public WrapModeType WrapModeU
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeU, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)WrapModeType.Default;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeU);
+ propertyValue?.Get(out ret);
+ return (WrapModeType)ret;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the wrap mode for the v coordinate.<br />
+ /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
+ /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
+ /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
+ /// For normal quad images only.
+ /// Optional.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public WrapModeType WrapModeV
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeV, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)WrapModeType.Default;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.WrapModeV);
+ propertyValue?.Get(out ret);
+ return (WrapModeType)ret;
+ }
+ }
+ #endregion
+
+ #region Decorated Visual Properties
+ /// <summary>
+ /// The radius for the rounded corners of the visual.
+ /// The values in Vector4 are used in clockwise order from top-left to bottom-left : Vector4(top-left-corner, top-right-corner, bottom-right-corner, bottom-left-corner).
+ /// Each radius will clamp internally to the half of smaller of the visual's width or height.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Vector4 CornerRadius
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius, new PropertyValue(value), false);
+ }
+ get
+ {
+ Vector4 ret = new Vector4();
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadius);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Whether the CornerRadius property value is relative (percentage [0.0f to 0.5f] of the visual size) or absolute (in world units).
+ /// It is absolute by default.
+ /// When the policy is relative, the corner radius is relative to the smaller of the visual's width and height.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType CornerRadiusPolicy
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy, new PropertyValue((int)value), false);
+ }
+ get
+ {
+ int ret = (int)VisualTransformPolicyType.Absolute;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.CornerRadiusPolicy);
+ propertyValue?.Get(out ret);
+ return (VisualTransformPolicyType)ret;
+ }
+ }
+
+ /// <summary>
+ /// The width for the borderline of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float BorderlineWidth
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth, new PropertyValue(value), false);
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineWidth);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The color for the borderline of the visual.
+ /// It is Color.Black by default.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Color BorderlineColor
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor, new PropertyValue(value), false);
+ }
+ get
+ {
+ Color ret = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineColor);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The Relative offset for the borderline of the visual.
+ /// Recommended range : [-1.0f to 1.0f].
+ /// If -1.0f, draw borderline inside of the visual.
+ /// If 1.0f, draw borderline outside of the visual.
+ /// If 0.0f, draw borderline half inside and half outside.
+ /// It is 0.0f by default.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float BorderlineOffset
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset, new PropertyValue(value), false);
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.BorderlineOffset);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ /// <summary>
+ /// Reload image.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Reload()
+ {
+ Interop.VisualObject.DoActionWithEmptyAttributes(SwigCPtr, ActionReload);
+ }
+ #endregion
+
+ #region Internal Methods
+ internal override void OnUpdateVisualPropertyMap()
+ {
+ // We should not create visual if url is invalid.
+ if (!isResourceUrlValid)
+ {
+ temperalStoredPropertyMap = cachedVisualPropertyMap;
+ cachedVisualPropertyMap = null;
+ }
+ }
+
+ internal override void OnVisualCreated()
+ {
+ if (temperalStoredPropertyMap != null)
+ {
+ cachedVisualPropertyMap = temperalStoredPropertyMap;
+ temperalStoredPropertyMap = null;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// The visual which can display an n-patch image resource.
+ /// It will be used when we want to display n-patch image, border only n-patch, or make regular image stretched.
+ /// </summary>
+ /// <remarks>
+ /// Following ImageVisual properties are not supported in NPatchVisual.
+ /// - CornerRadius
+ /// - BorderlineWidth
+ /// - AlphaMaskUrl
+ /// </remarks>
+ /// <remarks>
+ /// We assume that the image is a n-patch image always. So it does not support other image formats, like svg, lottie.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class NPatchVisual : ImageVisual
+ {
+ #region Constructor
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public NPatchVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal NPatchVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal NPatchVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ Type = (int)Tizen.NUI.Visual.Type.NPatch;
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// Gets or sets whether to draw the borders only (If true).<br />
+ /// If not specified, the default is false.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool BorderOnly
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.BorderOnly, new PropertyValue(value));
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.BorderOnly);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The border of the regular image is in the order: left, right, bottom, top.<br />
+ /// </summary>
+ /// <remarks>
+ /// Note that it is not mean the value from 9 patch image.<br />
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Rectangle Border
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.Border, (value == null) ? null : new PropertyValue(value));
+ }
+ get
+ {
+ Rectangle ret = new Rectangle();
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.NpatchImageVisualProperty.Border);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Overlays the auxiliary image on top of an NPatch image.
+ /// The resulting visual image will be at least as large as the smallest possible n-patch or the auxiliary image, whichever is larger.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string AuxiliaryImageUrl
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageURL, string.IsNullOrEmpty(value) ? null : new PropertyValue(value));
+ }
+ get
+ {
+ string ret = "";
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageURL);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// An alpha value for mixing between the masked main NPatch image and the auxiliary image.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float AuxiliaryImageAlpha
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageAlpha, new PropertyValue(value));
+ }
+ get
+ {
+ float ret = 1.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.ImageVisualProperty.AuxiliaryImageAlpha);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// The visual which can display simple text.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class TextVisual : VisualBase
+ {
+ #region Constructor
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public TextVisual() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal TextVisual(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal TextVisual(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ Type = (int)Tizen.NUI.Visual.Type.Text;
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// The Text property.<br />
+ /// The text to display in the UTF-8 format.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string Text
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.Text, new PropertyValue(string.IsNullOrEmpty(value) ? "" : value));
+ }
+ get
+ {
+ string ret = "";
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.Text);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The requested font family to use.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string FontFamily
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.FontFamily, new PropertyValue(string.IsNullOrEmpty(value) ? "" : value));
+ }
+ get
+ {
+ string ret = "";
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.FontFamily);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The size of font in points.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float PointSize
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.PointSize, new PropertyValue(value));
+ }
+ get
+ {
+ float ret = 0.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.PointSize);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The single-line or multi-line layout option.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool MultiLine
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.MultiLine, new PropertyValue(value));
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.MultiLine);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// The line horizontal alignment.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.HorizontalAlignment HorizontalAlignment
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.HorizontalAlignment, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)Tizen.NUI.HorizontalAlignment.Begin;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.HorizontalAlignment);
+ propertyValue?.Get(out ret);
+ return (Tizen.NUI.HorizontalAlignment)ret;
+ }
+ }
+
+ /// <summary>
+ /// The line vertical alignment.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.VerticalAlignment VerticalAlignment
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.VerticalAlignment, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)Tizen.NUI.VerticalAlignment.Top;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.VerticalAlignment);
+ propertyValue?.Get(out ret);
+ return (Tizen.NUI.VerticalAlignment)ret;
+ }
+ }
+
+ /// <summary>
+ /// The color of the text.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.Color TextColor
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.TextColor, new PropertyValue(value));
+ }
+ get
+ {
+ Tizen.NUI.Color ret = new Color(0.0f, 0.0f, 0.0f, 1.0f);
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.TextColor);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Whether the mark-up processing is enabled.<br />
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool EnableMarkup
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.TextVisualProperty.EnableMarkup, new PropertyValue(value));
+ }
+ get
+ {
+ bool ret = false;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.TextVisualProperty.EnableMarkup);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
--- /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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Linq;
+using System.ComponentModel;
+
+namespace Tizen.NUI.Visuals
+{
+ /// <summary>
+ /// The base class of all visual in namespace Tizen.NUI.Visuals.
+ /// This class is abstract class. We cannot use it without type of Properties.
+ /// </summary>
+ /// <remarks>
+ /// Visual is the smallest rendering unit that application can control without custom renderer.
+ /// It will be used when we want to add a new visual to the View.
+ /// We can change the size or offset of visuals, and sibling order.
+ ///
+ /// When we change the property of visual, the visual will be recreated at end of event loop.
+ /// </remarks>
+ /// <code>
+ /// animation.AnimateTo(view, "BorderlineOffset", -1.0f);
+ /// </code>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public class VisualBase : BaseHandle
+ {
+ #region Internal And Private
+ internal PropertyMap cachedVisualPropertyMap = null;
+ internal PropertyMap changedPropertyMap = null;
+
+ internal bool visualCreationRequiredFlag = true; // The first time should create visual.
+ internal bool visualUpdateRequiredFlag = false;
+
+ internal bool visualCreationManually = false;
+
+ private int internalType = (int)Tizen.NUI.Visual.Type.Invalid;
+
+ private bool visualPropertyUpdateProcessAttachedFlag = false;
+
+ private bool visualFittingModeApplied = false; // Whether we use fitting mode, or DontCare.
+
+ internal struct VisualTransformInfo
+ {
+ public float width;
+ public float height;
+ public float offsetX;
+ public float offsetY;
+
+ public VisualTransformPolicyType widthPolicy;
+ public VisualTransformPolicyType heightPolicy;
+ public VisualTransformPolicyType offsetXPolicy;
+ public VisualTransformPolicyType offsetYPolicy;
+
+ public Visual.AlignType origin;
+ public Visual.AlignType pivotPoint;
+
+ public float extraWidth;
+ public float extraHeight;
+
+ public PropertyMap cachedVisualTransformPropertyMap;
+
+ internal bool changed;
+
+ public void Clear()
+ {
+ width = 1.0f;
+ height = 1.0f;
+ offsetX = 0.0f;
+ offsetY = 0.0f;
+
+ widthPolicy = VisualTransformPolicyType.Relative;
+ heightPolicy = VisualTransformPolicyType.Relative;
+ offsetXPolicy = VisualTransformPolicyType.Relative;
+ offsetYPolicy = VisualTransformPolicyType.Relative;
+
+ origin = Visual.AlignType.TopBegin;
+ pivotPoint = Visual.AlignType.TopBegin;
+
+ extraWidth = 0.0f;
+ extraHeight = 0.0f;
+
+ cachedVisualTransformPropertyMap = null;
+
+ changed = true;
+ }
+
+ internal void ConvertToPropertyMap()
+ {
+ if (cachedVisualTransformPropertyMap == null)
+ {
+ cachedVisualTransformPropertyMap = new PropertyMap();
+ }
+
+ cachedVisualTransformPropertyMap.Clear();
+ cachedVisualTransformPropertyMap.Add((int)VisualTransformPropertyType.Size, new PropertyValue(new Vector2(width, height)))
+ .Add((int)VisualTransformPropertyType.Offset, new PropertyValue(new Vector2(offsetX, offsetY)))
+ .Add((int)VisualTransformPropertyType.SizePolicy, new PropertyValue(new Vector2((float)widthPolicy, (float)heightPolicy)))
+ .Add((int)VisualTransformPropertyType.OffsetPolicy, new PropertyValue(new Vector2((float)offsetXPolicy, (float)offsetYPolicy)))
+ .Add((int)VisualTransformPropertyType.Origin, new PropertyValue((int)origin))
+ .Add((int)VisualTransformPropertyType.AnchorPoint, new PropertyValue((int)pivotPoint))
+ .Add((int)VisualTransformPropertyType.ExtraSize, new PropertyValue(new Vector2(extraWidth, extraHeight)));
+ }
+
+ internal void ConvertFromPropertyMap(PropertyMap inputMap)
+ {
+ PropertyValue value = null;
+
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.Size)) != null)
+ {
+ using var size = new Size();
+ if (value.Get(size))
+ {
+ width = size.Width;
+ height = size.Height;
+ }
+ }
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.Offset)) != null)
+ {
+ using var offset = new Position();
+ if (value.Get(offset))
+ {
+ offsetX = offset.X;
+ offsetY = offset.Y;
+ }
+ }
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.SizePolicy)) != null)
+ {
+ using var policyValue = new Vector2();
+ if (value.Get(policyValue))
+ {
+ widthPolicy = (VisualTransformPolicyType)policyValue.X;
+ heightPolicy = (VisualTransformPolicyType)policyValue.Y;
+ }
+ }
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.OffsetPolicy)) != null)
+ {
+ using var policyValue = new Vector2();
+ if (value.Get(policyValue))
+ {
+ offsetXPolicy = (VisualTransformPolicyType)policyValue.X;
+ offsetYPolicy = (VisualTransformPolicyType)policyValue.Y;
+ }
+ }
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.Origin)) != null)
+ {
+ int ret = 0;
+ if (value.Get(out ret))
+ {
+ origin = (Visual.AlignType)ret;
+ }
+ }
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.AnchorPoint)) != null)
+ {
+ int ret = 0;
+ if (value.Get(out ret))
+ {
+ pivotPoint = (Visual.AlignType)ret;
+ }
+ }
+ if ((value = inputMap?.Find((int)VisualTransformPropertyType.ExtraSize)) != null)
+ {
+ using var extraValue = new Vector2();
+ if (value.Get(extraValue))
+ {
+ extraWidth = extraValue.Width;
+ extraHeight = extraValue.Height;
+ }
+ }
+ value?.Dispose();
+ }
+ };
+ internal VisualTransformInfo transformInfo;
+ #endregion
+
+ #region Constructor
+ /// <summary>
+ /// Creates an visual object.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualBase() : this(Interop.VisualObject.VisualObjectNew(), true)
+ {
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ internal VisualBase(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn)
+ {
+ }
+
+ internal VisualBase(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, cRegister)
+ {
+ transformInfo.Clear();
+ }
+ #endregion
+
+ #region Enum
+ /// <summary>
+ /// The update mode of this VisualBase property.
+ /// Default is Auto.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public enum PropertyUpdateModeType
+ {
+ /// <summary>
+ /// Update property automatically, by NUI event loop.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Auto,
+ /// <summary>
+ /// Update property manually.
+ /// Need to call <see cref="UpdateProperty"/> function manually to update property.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ Manual,
+ }
+ #endregion
+
+ #region Properties
+ /// <summary>
+ /// Sibling order of this VisualBase.
+ /// </summary>
+ /// <remarks>
+ /// The sibling order is used to determine the draw order of the visuals.
+ /// The visuals with smaller sibling order are drawn bottom,
+ /// and the visuals with larger sibling order are drawn top.
+ ///
+ /// It will be changed automatically when the visuals are added to the view.
+ /// The default value is 0.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public uint SiblingOrder
+ {
+ set
+ {
+ Interop.VisualObject.SetSiblingOrder(SwigCPtr, value);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+ get
+ {
+ uint ret = Interop.VisualObject.GetSiblingOrder(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Type of this VisualObject. It will be set at construction time.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int Type
+ {
+ internal set
+ {
+ if(internalType != value)
+ {
+ internalType = value;
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.Type, new PropertyValue(value), true);
+ }
+ }
+ get
+ {
+ return internalType;
+ }
+ }
+
+ /// <summary>
+ /// Name of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// The way of visual property update.
+ /// Default is PropertyUpdateModeType.Auto.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public PropertyUpdateModeType PropertyUpdateMode
+ {
+ set
+ {
+ visualCreationManually = (value == PropertyUpdateModeType.Manual);
+ }
+ get
+ {
+ return visualCreationManually ? PropertyUpdateModeType.Manual : PropertyUpdateModeType.Auto;
+ }
+ }
+ #endregion
+
+ #region Visual Properties
+ /// <summary>
+ /// Color for the visual. Default color is White
+ /// </summary>
+ /// <remarks>
+ /// This is exclusive with the Opacity property.
+ /// Opacity property be applied as Color.A.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.Color Color
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.MixColor, new PropertyValue(value), false);
+
+ // warning : We should set cached Opacity after set MixColor.
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.Opacity, new PropertyValue(value.A), false);
+ }
+ get
+ {
+ Tizen.NUI.Color ret = new Tizen.NUI.Color(1.0f, 1.0f, 1.0f, 1.0f);
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.MixColor);
+ propertyValue?.Get(ret);
+ return ret;
+ }
+ }
+
+ /// <summary>
+ /// Opacity for the visual.
+ /// </summary>
+ /// <remarks>
+ /// This is exclusive with the Color property.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float Opacity
+ {
+ set
+ {
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.Opacity, new PropertyValue(value), false);
+ }
+ get
+ {
+ float ret = 1.0f;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.Opacity);
+ propertyValue?.Get(out ret);
+ return ret;
+ }
+ }
+ #endregion
+
+ #region Visual Transform Properties
+ /// <summary>
+ /// FittingMode for the visual.
+ /// </summary>
+ /// <remarks>
+ /// The fitting mode is used to decide how the visual should be fitted to the control area.
+ /// The default value is VisualFittingModeType.DontCare.
+ /// If user set one of Transform property, it will be set as VisualFittingModeType.DontCare automatically.
+ /// </remarks>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualFittingModeType FittingMode
+ {
+ set
+ {
+ if (value != VisualFittingModeType.DontCare)
+ {
+ visualFittingModeApplied = true;
+ }
+ else
+ {
+ visualFittingModeApplied = false;
+ }
+ UpdateVisualProperty((int)Tizen.NUI.Visual.Property.VisualFittingMode, new PropertyValue((int)value));
+ }
+ get
+ {
+ int ret = (int)VisualFittingModeType.DontCare;
+ var propertyValue = GetCachedVisualProperty((int)Tizen.NUI.Visual.Property.VisualFittingMode);
+ propertyValue?.Get(out ret);
+ return (VisualFittingModeType)ret;
+ }
+ }
+
+ /// <summary>
+ /// Width of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float Width
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.width != value)
+ {
+ transformInfo.width = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.width;
+ }
+ }
+
+ /// <summary>
+ /// Height of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float Height
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.height != value)
+ {
+ transformInfo.height = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.height;
+ }
+ }
+
+ /// <summary>
+ /// Policy of width.
+ /// If it is Relative, The width will be relative by the View's width.
+ /// If it is Absolute, The width will be used as the absolute Width value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType WidthPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.widthPolicy != value)
+ {
+ transformInfo.widthPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.widthPolicy;
+ }
+ }
+
+ /// <summary>
+ /// Policy of height.
+ /// If it is Relative, The height will be relative by the View's height.
+ /// If it is Absolute, The height will be used as the absolute Height value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType HeightPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.heightPolicy != value)
+ {
+ transformInfo.heightPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.heightPolicy;
+ }
+ }
+
+ /// <summary>
+ /// OffsetX of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float OffsetX
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetX != value)
+ {
+ transformInfo.offsetX = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetX;
+ }
+ }
+
+ /// <summary>
+ /// OffsetY of the visual.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float OffsetY
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetY != value)
+ {
+ transformInfo.offsetY = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetY;
+ }
+ }
+
+ /// <summary>
+ /// Policy of offsetX.
+ /// If it is Relative, The offsetX will be relative by the View's width.
+ /// If it is Absolute, The offsetX will be used as the absolute OffsetX value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType OffsetXPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetXPolicy != value)
+ {
+ transformInfo.offsetXPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetXPolicy;
+ }
+ }
+
+ /// <summary>
+ /// Policy of offsetY.
+ /// If it is Relative, The offsetY will be relative by the View's height.
+ /// If it is Absolute, The offsetY will be used as the absolute OffsetY value.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public VisualTransformPolicyType OffsetYPolicy
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.offsetYPolicy != value)
+ {
+ transformInfo.offsetYPolicy = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.offsetYPolicy;
+ }
+ }
+
+ /// <summary>
+ /// Origin of the visual from view.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Visual.AlignType Origin
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.origin != value)
+ {
+ transformInfo.origin = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.origin;
+ }
+ }
+
+ /// <summary>
+ /// Pivot point of the visual from view.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Visual.AlignType PivotPoint
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.pivotPoint != value)
+ {
+ transformInfo.pivotPoint = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.pivotPoint;
+ }
+ }
+
+ /// <summary>
+ /// Extra width of the visual as absolute policy.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float ExtraWidth
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.extraWidth != value)
+ {
+ transformInfo.extraWidth = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.extraWidth;
+ }
+ }
+
+ /// <summary>
+ /// Extra height of the visual as absolute policy.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public float ExtraHeight
+ {
+ set
+ {
+ if (visualFittingModeApplied)
+ {
+ FittingMode = VisualFittingModeType.DontCare;
+ }
+ if (transformInfo.extraHeight != value)
+ {
+ transformInfo.extraHeight = value;
+ TransformPropertyChanged();
+ }
+ }
+ get
+ {
+ return transformInfo.extraHeight;
+ }
+ }
+ #endregion
+
+ #region Public Methods
+ /// <summary>
+ /// Get attached View.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public Tizen.NUI.BaseComponents.View GetOwner()
+ {
+ var container = GetVisualContainer();
+ if (container != null)
+ {
+ return container.GetView();
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Detach from View.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Detach()
+ {
+ if (Disposed)
+ {
+ return;
+ }
+
+ var container = GetVisualContainer();
+ if (container != null)
+ {
+ container.RemoveVisualObject(this);
+ }
+
+ Interop.VisualObject.Detach(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Raise above the next sibling visual object
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Raise()
+ {
+ Interop.VisualObject.Raise(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Lower below the previous sibling visual object
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void Lower()
+ {
+ Interop.VisualObject.Lower(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Raise above all other sibling visual objects
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RaiseToTop()
+ {
+ Interop.VisualObject.RaiseToTop(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Raise below all other sibling visual objects
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void LowerToBottom()
+ {
+ Interop.VisualObject.LowerToBottom(SwigCPtr);
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Raise above target visual objects. No effects if visual object is already above target.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void RaiseAbove(Visuals.VisualBase target)
+ {
+ Interop.VisualObject.RaiseAbove(SwigCPtr, Visuals.VisualBase.getCPtr(target));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Lower below target visual objects. No effects if visual object is already below target.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void LowerBelow(Visuals.VisualBase target)
+ {
+ Interop.VisualObject.LowerBelow(SwigCPtr, Visuals.VisualBase.getCPtr(target));
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Update visual properties manually.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void UpdateProperty()
+ {
+ UpdateVisualPropertyMap();
+ }
+ #endregion
+
+ #region Internal Methods
+ internal Visuals.VisualObjectsContainer GetVisualContainer()
+ {
+ global::System.IntPtr cPtr = Interop.VisualObject.GetContainer(SwigCPtr);
+ Visuals.VisualObjectsContainer ret = null;
+ if (Interop.RefObject.GetRefObjectPtr(cPtr) == global::System.IntPtr.Zero)
+ {
+ // Visual contianer is not created yet. Return null.
+ Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+ }
+ else
+ {
+ ret = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Visuals.VisualObjectsContainer;
+ if (ret != null)
+ {
+ Interop.BaseHandle.DeleteBaseHandle(new global::System.Runtime.InteropServices.HandleRef(this, cPtr));
+ }
+ else
+ {
+ ret = new Visuals.VisualObjectsContainer(cPtr, true);
+ }
+ }
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ return ret;
+ }
+
+ /// <summary>
+ /// Unregister visual from control. It will not remove cached data.
+ /// </summary>
+ internal void UnregisterVisual()
+ {
+ using var tempPropertyMap = new PropertyMap();
+ Interop.VisualObject.CreateVisual(SwigCPtr, PropertyMap.getCPtr(tempPropertyMap));
+ }
+
+ /// <summary>
+ /// Set or Get visual property.
+ /// </summary>
+ /// <remarks>
+ /// This property might change the type of visual. We should not set it from subclass of VisualBase.
+ /// </remarks>
+ internal PropertyMap Properties
+ {
+ private set
+ {
+ visualCreationRequiredFlag = true;
+ cachedVisualPropertyMap = value;
+
+ visualUpdateRequiredFlag = false;
+ changedPropertyMap?.Dispose();
+ changedPropertyMap = null;
+
+ transformInfo.Clear();
+
+ // Get transform informations from input property map.
+ using var transformValue = cachedVisualPropertyMap?.Find((int)Tizen.NUI.Visual.Property.Transform);
+ if (transformValue != null)
+ {
+ PropertyMap transformMap = new PropertyMap();
+ if (transformValue.Get(ref transformMap) && transformMap != null)
+ {
+ transformInfo.ConvertFromPropertyMap(transformMap);
+ }
+ }
+ transformInfo.changed = false;
+
+ // Get type from the property map.
+ internalType = (int)Tizen.NUI.Visual.Type.Invalid;
+ if (cachedVisualPropertyMap?.Find((int)Tizen.NUI.Visual.Property.Type)?.Get(out internalType) ?? false)
+ {
+ UpdateVisualPropertyMap();
+ }
+ else
+ {
+ // If type is not set, then remove the visual.
+ UnregisterVisual();
+ }
+ }
+ get
+ {
+ // Sync as current properties
+ UpdateVisualPropertyMap();
+
+ PropertyMap ret = new PropertyMap();
+ Interop.VisualObject.RetrieveVisualPropertyMap(SwigCPtr, PropertyMap.getCPtr(ret));
+ return ret;
+ }
+ }
+
+ virtual internal void OnUpdateVisualPropertyMap()
+ {
+ }
+
+ virtual internal void OnVisualCreated()
+ {
+ }
+
+ /// <summary>
+ /// Lazy call to UpdateVisualPropertyMap.
+ /// Collect Properties need to be update, and set properties that starts the Processing.
+ ///
+ /// If you want to update cachedVisualPropertyMap, but don't want to request new visual creation, make requiredVisualCreation value as false.
+ /// (Example : if we change SynchronousLoading property from 'true' to 'false', or if we call this function during OnUpdateVisualPropertyMap)
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ virtual internal void UpdateVisualProperty(int key, PropertyValue value, bool requiredVisualCreation = true)
+ {
+ // Update visual property map value as inputed value.
+ if (key != 0)
+ {
+ if (!HasBody())
+ {
+ // Throw exception if VisualBase is disposed.
+ throw new global::System.InvalidOperationException($"[NUI][VisualBase] Someone try to change disposed VisualBase property.\n");
+ }
+
+ if (cachedVisualPropertyMap == null)
+ {
+ cachedVisualPropertyMap = new PropertyMap();
+ }
+
+ visualCreationRequiredFlag |= requiredVisualCreation;
+ if (value != null)
+ {
+ cachedVisualPropertyMap[key] = value;
+
+ // Store the changed values in the changedPropertyMap, only if visualCreationRequiredFlag is false.
+ // It will be used when we create the visual, only by UpdateVisualPropertyMap
+ if (!visualCreationRequiredFlag)
+ {
+ visualUpdateRequiredFlag = true;
+ if (changedPropertyMap == null)
+ {
+ changedPropertyMap = new PropertyMap();
+ }
+ changedPropertyMap[key] = value;
+ }
+ }
+ else
+ {
+ // Remove value from cachedVisualPropertyMap if input property map is null.
+ cachedVisualPropertyMap.Remove(key);
+ }
+
+ ReqeustProcessorOnceEvent();
+ }
+ }
+
+ internal void UpdateVisualPropertyMap(object o, global::System.EventArgs e)
+ {
+ // Note : To allow event attachment during UpdateVisualPropertyMap, let we make flag as false before call UpdateVisualPropertyMap().
+ visualPropertyUpdateProcessAttachedFlag = false;
+ if (!visualCreationManually)
+ {
+ UpdateVisualPropertyMap();
+ }
+ }
+
+ internal void UpdateVisualPropertyMap()
+ {
+ if (Disposed)
+ {
+ return;
+ }
+
+ if (internalType == (int)Tizen.NUI.Visual.Type.Invalid)
+ {
+ Tizen.Log.Error("NUI", "Invalid visual type.\n");
+ return;
+ }
+
+ if (!visualCreationRequiredFlag)
+ {
+ if (visualUpdateRequiredFlag && changedPropertyMap != null)
+ {
+ // We can change property map of visuals without creating them.
+ Interop.VisualObject.UpdateVisualPropertyMap(SwigCPtr, PropertyMap.getCPtr(changedPropertyMap));
+
+ changedPropertyMap?.Dispose();
+ changedPropertyMap = null;
+ }
+ return;
+ }
+
+ visualCreationRequiredFlag = false;
+ visualUpdateRequiredFlag = false;
+
+ changedPropertyMap?.Dispose();
+ changedPropertyMap = null;
+
+ if (cachedVisualPropertyMap == null)
+ {
+ cachedVisualPropertyMap = new PropertyMap();
+ }
+
+ if (transformInfo.changed)
+ {
+ transformInfo.changed = false;
+ cachedVisualPropertyMap.Remove((int)Tizen.NUI.Visual.Property.Transform);
+
+ transformInfo.ConvertToPropertyMap();
+
+ if (transformInfo.cachedVisualTransformPropertyMap != null)
+ {
+ using var transformValue = new PropertyValue(transformInfo.cachedVisualTransformPropertyMap);
+ cachedVisualPropertyMap.Add((int)Tizen.NUI.Visual.Property.Transform, transformValue);
+ }
+ }
+
+ // Update the sub classes property map.
+ OnUpdateVisualPropertyMap();
+
+ Interop.VisualObject.CreateVisual(SwigCPtr, PropertyMap.getCPtr(cachedVisualPropertyMap));
+
+ // Post process for sub classes.
+ OnVisualCreated();
+
+ NDalicPINVOKE.ThrowExceptionIfExists();
+ }
+
+ /// <summary>
+ /// Get visual property by key.
+ /// If we found value in local cached result, return that.
+ /// Else, get synced native map and return that.
+ /// </summary>
+ /// <returns>Matched value. If there is no matched value, return null.</returns>
+ internal PropertyValue GetVisualProperty(int key)
+ {
+ PropertyValue ret = GetCachedVisualProperty(key);
+ if (ret == null)
+ {
+ // If we cannot find result from cached map, Get value from native engine.
+ GetCurrentVisualProperty(key);
+ }
+ return ret;
+ }
+
+ /// <summary>
+ /// Get visual property by key from native engine.
+ /// </summary>
+ /// <returns>Matched value. If there is no matched value, return null.</returns>
+ internal PropertyValue GetCurrentVisualProperty(int key)
+ {
+ return Properties?.Find(key);
+ }
+
+ /// <summary>
+ /// Get visual property from NUI cached map by key.
+ /// </summary>
+ /// <returns>Matched value. If there is no matched value, return null.</returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal virtual PropertyValue GetCachedVisualProperty(int key)
+ {
+ return cachedVisualPropertyMap?.Find(key);
+ }
+
+ /// <summary>
+ /// Change visual transform information.
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal void TransformPropertyChanged()
+ {
+ if (transformInfo.cachedVisualTransformPropertyMap == null)
+ {
+ transformInfo.cachedVisualTransformPropertyMap = new PropertyMap();
+ }
+
+ // Mark as transform property map.
+ visualCreationRequiredFlag = true;
+ transformInfo.changed = true;
+
+ ReqeustProcessorOnceEvent();
+ }
+
+ internal void ReqeustProcessorOnceEvent()
+ {
+ if (!visualCreationManually && !visualPropertyUpdateProcessAttachedFlag)
+ {
+ visualPropertyUpdateProcessAttachedFlag = true;
+ ProcessorController.Instance.ProcessorOnceEvent += UpdateVisualPropertyMap;
+ // Call process hardly.
+ ProcessorController.Instance.Awake();
+ }
+ }
+
+ /// <summary>
+ /// Dispose for VisualObject
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ protected override void Dispose(DisposeTypes type)
+ {
+ if (Disposed)
+ {
+ return;
+ }
+
+ if (type == DisposeTypes.Explicit)
+ {
+ //Called by User
+ //Release your own managed resources here.
+ //You should release all of your own disposable objects here.
+
+ // Note : Do not call this function in Implicit dispose case.
+ // Since if visual is already under some VisualObjectsContainer,
+ // it will never be GC.
+ Detach();
+ }
+
+ visualCreationRequiredFlag = false;
+ visualUpdateRequiredFlag = false;
+
+ changedPropertyMap?.Dispose();
+ changedPropertyMap = null;
+ cachedVisualPropertyMap?.Dispose();
+ cachedVisualPropertyMap = null;
+
+ base.Dispose(type);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
BottomRight = 8,
}
-
/// <summary>
/// The stage instance property (read-only).<br />
/// Gets the current window.<br />
/// </summary>
- /// <since_tizen> 3 </since_tizen>
+ [Obsolete("This has been deprecated in API12, please use Default instead")]
public static Window Instance { get; internal set; }
/// <summary>
+ /// Gets the default window.
+ /// The main window or default window is automatically created when the application is launched,
+ /// and it remains constant and unchanged throughout the application's operation.
+ /// </summary>
+ /// <since_tizen> 12 </since_tizen>
+ public static Window Default { get; internal set; }
+
+ /// <summary>
/// Gets or sets a window type.
/// Most of window type can be set to use WindowType, except for IME type.
/// IME type can be set to use one of NUIApplication's constrcutors.
--- /dev/null
+<Project Sdk="Tizen.NET.Sdk/1.1.9">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net6.0</TargetFramework>
+ <AssemblyName>AIAvatarSample</AssemblyName>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugType>portable</DebugType>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>None</DebugType>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\..\src\Tizen.AIAvatar\Tizen.AIAvatar.csproj" />
+ <ProjectReference Include="../../src/Tizen.NUI.Components/Tizen.NUI.Components.csproj" />
+ </ItemGroup>
+</Project>
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34009.444
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.AIAvatar.Sample", "Tizen.AIAvatar.Sample.csproj", "{0176A159-FCC2-45B8-ABEE-63FEBFEA5079}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.AIAvatar", "..\..\src\Tizen.AIAvatar\Tizen.AIAvatar.csproj", "{D1971AA8-5B1D-467A-9E86-292B01C4DDB8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0176A159-FCC2-45B8-ABEE-63FEBFEA5079}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1971AA8-5B1D-467A-9E86-292B01C4DDB8}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- /dev/null
+/*
+ * Copyright(c) 2023 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 global::System;
+using System.IO;
+using System.Collections.Generic;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Scene3D;
+using Tizen.AIAvatar;
+using Tizen;
+using Tizen.Uix.Tts;
+
+namespace AIAvatar
+{
+ public class AvatarScene : SceneView
+ {
+ private static readonly string ApplicationResourcePath = "/usr/apps/org.tizen.default-avatar-resource/shared/res/";
+ private static readonly string EmojiAvatarResourcePath = "/models/EmojiAvatar/";
+ private static readonly string DefaultMotionResourcePath = "/animation/motion/";
+ private static string resourcePath = Utils.ResourcePath;
+
+ private const int cameraAnimationDurationMilliSeconds = 2000;
+ private const int sceneTransitionDurationMilliSeconds = 1500;
+
+ private Avatar defaultAIAvatar;
+ private List<AvatarInfo> avatarList;
+ private List<AnimationInfo> animationInfoList;
+ private LipSyncController lipSyncController;
+
+ private bool isBlink = false;
+ private bool isShowing = true;
+
+ private int avatarIndex = 0;
+ private float iblFactor = 0.3f;
+
+ public float IBLFactor
+ {
+ get
+ {
+ return iblFactor;
+ }
+ set
+ {
+ iblFactor = value;
+ ImageBasedLightScaleFactor = value;
+ }
+ }
+
+ public AvatarScene()
+ {
+ PivotPoint = Tizen.NUI.PivotPoint.TopLeft;
+ ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft;
+ PositionUsesPivotPoint = true;
+
+ // Setup Image Based Light
+ SetupSceneViewIBL();
+
+ // Setup camera preset
+ SetupDefaultCamera();
+
+ // Setup Default Avatar Position & Orientation
+ SetupDefaultAvatar();
+
+ // Load Default Animations
+ LoadDefaultAnimations();
+ }
+
+ private void LoadDefaultAnimations()
+ {
+ var motionAnimations = Directory.GetFiles(ApplicationResourcePath + DefaultMotionResourcePath, "*.bvh");
+ animationInfoList = new List<AnimationInfo>();
+
+ foreach (var path in motionAnimations)
+ {
+ var motionData = new MotionData();
+ motionData.LoadMotionCaptureAnimation(path, true, new Vector3(0.01f, 0.01f, 0.01f), false);
+
+ var animationInfo = new AnimationInfo(motionData, GetFileNameWithoutExtension(path));
+ animationInfoList.Add(animationInfo);
+ }
+ }
+
+ public void SetupSceneViewIBLFactor(float value)
+ {
+ IBLFactor = value;
+ }
+
+ public void StartAvatarTalk_1()
+ {
+ PlayLip("cs-CZ-Wavenet-A.wav");
+ }
+
+ public void StartAvatarTalk_2()
+ {
+ PlayLip("da-DK-Wavenet-A.wav");
+ }
+
+ public void StartAvatarTalk_3()
+ {
+ PlayLip("el-GR-Wavenet-A.wav");
+ }
+
+ public void StartAvatarTalkByPath()
+ {
+ PlayLip($"{resourcePath}/voice/voice_0.bin");
+ }
+
+ private void PlayLip(string source)
+ {
+ var path = $"{resourcePath}/voice/{source}";
+ var bytes = ReadAllBytes(path);
+
+ Tizen.Log.Error("AIAvatar", "audio path : " + path);
+ if (lipSyncController == null)
+ {
+ lipSyncController = new LipSyncController(defaultAIAvatar);
+ }
+
+ if (bytes != null)
+ {
+ lipSyncController.PlayLipSync(bytes);
+ }
+ else
+ {
+ Tizen.Log.Error("AIAvatar", "Fail to load bytes");
+ }
+ }
+
+ public void StartRandomAnimation()
+ {
+ var randomIdx = new Random().Next(0, animationInfoList.Count);
+ defaultAIAvatar.PlayAnimation(animationInfoList[randomIdx].MotionData);
+ }
+
+ public void StartMic()
+ {
+ InitMic();
+ lipSyncController?.StartMic();
+ }
+
+ public void StopMic()
+ {
+ InitMic();
+ lipSyncController?.StopMic();
+ }
+
+ public void EyeBlink()
+ {
+ if (!isBlink)
+ {
+ defaultAIAvatar.StartEyeBlink();
+ }
+ else
+ {
+ defaultAIAvatar.StopEyeBlink();
+ }
+ isBlink = !isBlink;
+ }
+
+ public void ShowHide()
+ {
+ if (!isShowing)
+ {
+ defaultAIAvatar.Show();
+ }
+ else
+ {
+ defaultAIAvatar.Hide();
+ }
+ isShowing = !isShowing;
+ }
+
+ public void InintTTsTest()
+ {
+ InitTTS();
+ }
+
+ public void StartTTSTest()
+ {
+ lipSyncController.StopTTS();
+ VoiceInfo voiceInfo = new VoiceInfo()
+ {
+ Language = "en_US",
+ Type = VoiceType.Female,
+ };
+
+ lipSyncController.PrepareTTS(Utils.TTSText, voiceInfo, (o, e) =>
+ {
+ lipSyncController.PlayPreparedTTS();
+ });
+ }
+
+ public void StopTTSTest()
+ {
+ if (lipSyncController == null)
+ {
+ Tizen.Log.Error("AIAvatar", "lipSyncController is null");
+ return;
+ }
+ lipSyncController.StopTTS();
+ }
+
+ public void SwitchCamera()
+ {
+ CameraTransition(1, cameraAnimationDurationMilliSeconds);
+ }
+
+ public void SetupSceneViewCameraFov(float value)
+ {
+ var camera = GetSelectedCamera();
+ camera.FieldOfView = new Radian(value);
+ }
+
+ public void ChangeAvatar()
+ {
+ DestroyAvatar();
+ if (avatarIndex + 1 <= avatarList.Count - 1)
+ {
+ avatarIndex++;
+ }
+ else
+ {
+ avatarIndex = 0;
+ }
+ CreateAvatar();
+
+ }
+
+ internal static string GetFileNameWithoutExtension(string path)
+ {
+ return System.IO.Path.GetFileNameWithoutExtension(path);
+ }
+
+ private void InitTTS()
+ {
+ if (lipSyncController == null)
+ {
+ lipSyncController = new LipSyncController(defaultAIAvatar);
+ }
+ lipSyncController.InitializeTTS();
+ }
+
+ private void InitMic()
+ {
+ if (lipSyncController == null)
+ {
+ lipSyncController = new LipSyncController(defaultAIAvatar);
+ }
+ lipSyncController.InitializeMic();
+ }
+
+ private byte[] ReadAllBytes(string path)
+ {
+ try
+ {
+ var bytes = File.ReadAllBytes(path);
+ return bytes;
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ private void SetupDefaultAvatar()
+ {
+ avatarList = AvatarExtension.GetDefaultAvatarList();
+ foreach (var info in avatarList)
+ {
+ Tizen.Log.Info("AvatarSample", $"Avatar Name :{info.Name}\n");
+ Tizen.Log.Info("AvatarSample", $"Avatar Thumbnail :{info.ThumbnailPath}\n");
+ }
+
+ CreateAvatar();
+ }
+
+ private void CreateAvatar()
+ {
+ defaultAIAvatar = new Avatar(avatarList[avatarIndex])
+ {
+ Position = new Position(0.0f, -1.70f, -2.0f),
+ Size = new Size(1.0f, 1.0f, 1.0f),
+ Orientation = new Rotation(new Radian(new Degree(0.0f)), Vector3.YAxis)
+ };
+ //var animator = defaultAIAvatar.CurrentAnimator;
+ //animator.MotionStateChanged += OnMotionStateChanged;
+ //animator.LipStateChanged += OnLipStateChanged;
+ Add(defaultAIAvatar);
+ }
+
+ private void DestroyAvatar()
+ {
+ if (defaultAIAvatar != null)
+ {
+ Remove(defaultAIAvatar);
+ /*
+ var animator = defaultAIAvatar.CurrentAnimator;
+ animator.MotionStateChanged -= OnMotionStateChanged;
+ animator.LipStateChanged -= OnLipStateChanged;
+*/
+ defaultAIAvatar.Dispose();
+ defaultAIAvatar = null;
+ }
+
+ }
+
+ private void OnMotionStateChanged(object sender, AvatarMotionChangedEventArgs e)
+ {
+ var avatar = sender as Avatar;//Avatar changed state
+
+ switch (e.Current)
+ {
+ case AvatarMotionState.Ready:
+ Log.Error(Utils.LogTag, "Current Avatar State is Ready");
+ break;
+
+ case AvatarMotionState.Playing:
+ Log.Error(Utils.LogTag, "Current Avatar State is Playing");
+ break;
+
+ case AvatarMotionState.Paused:
+ Log.Error(Utils.LogTag, "Current Avatar State is Paused");
+ break;
+
+ case AvatarMotionState.Stopped:
+ Log.Error(Utils.LogTag, "Current Avatar State is Stopped");
+ break;
+ }
+ }
+
+ private void OnLipStateChanged(object sender, AvatarMotionChangedEventArgs e)
+ {
+ var avatar = sender as Avatar;//Avatar changed state
+
+ switch (e.Current)
+ {
+ case AvatarMotionState.Ready:
+ Log.Error(Utils.LogTag, "Current Avatar Lip is Ready");
+ break;
+
+ case AvatarMotionState.Playing:
+ Log.Error(Utils.LogTag, "Current Avatar Lip is Playing");
+ break;
+
+ case AvatarMotionState.Paused:
+ Log.Error(Utils.LogTag, "Current Avatar Lip is Paused");
+ break;
+
+ case AvatarMotionState.Stopped:
+ Log.Error(Utils.LogTag, "Current Avatar Lip is Stopped");
+ break;
+ }
+ }
+
+ private void SetupSceneViewIBL()
+ {
+ SetImageBasedLightSource(resourcePath + "images/" + "Irradiance.ktx", resourcePath + "images/" + "Radiance.ktx", IBLFactor);
+ }
+
+ private void SetupDefaultCamera()
+ {
+ // Default camera setting
+ // Note : SceneView always have 1 default camera.
+ var defaultCamera = GetCamera(0u);
+
+ defaultCamera.PositionX = 0.0f;
+ defaultCamera.PositionY = -2.3f;
+ defaultCamera.PositionZ = 0.0f;
+ defaultCamera.FieldOfView = new Radian(new Degree(45.0f));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2023 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 global::System;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Scene3D;
+using Tizen.NUI.Components;
+
+namespace AIAvatar
+{
+ public class UIControlPanel
+ {
+ private readonly Vector2 SceneViewPadding = new Vector2(0.0f, 0.0f);
+ private ButtonStyle buttonStyle;
+ private SliderStyle sliderStyle;
+
+ private Window uiWindow;
+ private AvatarScene mainScene;
+ private View controlPannel;
+
+ private TextField editor;
+
+ private readonly float ControlPannelWidthScale = 0.25f;// Relative size of window width. windowSize.Width * 0.5f
+
+ public event EventHandler OnExitButtonClicked;
+
+ public void MakeControlPannel(Window uiWindow, AvatarScene mainScene)
+ {
+ this.uiWindow = uiWindow;
+ this.mainScene = mainScene;
+
+ if (controlPannel != null)
+ {
+ return;
+ }
+
+ InitializeButtonStyle();
+ InitializeSliderStyle();
+
+ controlPannel = new ScrollableBase()
+ {
+ BackgroundColor = new Color(0.85f, 0.85f, 0.85f, 0.25f),
+
+ PivotPoint = PivotPoint.TopLeft,
+ ParentOrigin = ParentOrigin.TopLeft,
+ PositionUsesPivotPoint = true,
+ //CornerRadius = 30.0f,
+ Padding = new Extents(30, 30, 30, 30),
+
+ Layout = new LinearLayout()
+ {
+ LinearOrientation = LinearLayout.Orientation.Vertical,
+ HorizontalAlignment = HorizontalAlignment.Begin,
+ VerticalAlignment = VerticalAlignment.Top,
+ CellPadding = new Size2D(10, 20),
+ },
+ HideScrollbar = false,
+ };
+ uiWindow.Add(controlPannel);
+
+ // Make control buttons
+ MakeControlPannelComponents();
+ }
+
+ public void ReizeUIPanel(View avatarScene, View circleView)
+ {
+ var windowSize = uiWindow.Size;
+ var layoutLTR = (windowSize.Width >= windowSize.Height);
+
+ var sceneViewSize = new Vector2(0, 0);
+ var sceneViewPosition = new Vector2(0, 0);
+ var controlPannelSize = new Vector2(0, 0);
+ var controlPannelPosition = new Vector2(0, 0);
+ if (layoutLTR) // layout Left to Right
+ {
+ sceneViewSize = new Vector2(windowSize.Width - SceneViewPadding.X * 3.0f - ControlPannelWidthScale * windowSize.Width,
+ windowSize.Height - SceneViewPadding.Y * 2.0f);
+ sceneViewPosition = new Vector2(SceneViewPadding.X * 2.0f + ControlPannelWidthScale * windowSize.Width, SceneViewPadding.Y);
+ controlPannelSize = new Vector2(ControlPannelWidthScale * windowSize.Width, windowSize.Height - SceneViewPadding.Y * 2.0f);
+ controlPannelPosition = new Vector2(SceneViewPadding.X, SceneViewPadding.Y);
+ }
+ else // layout Top to Bottom
+ {
+ sceneViewSize = new Vector2(windowSize.Width - SceneViewPadding.X * 2.0f,
+ windowSize.Height - SceneViewPadding.Y * 3.0f - ControlPannelWidthScale * windowSize.Height);
+ sceneViewPosition = new Vector2(SceneViewPadding.X, SceneViewPadding.Y * 2.0f + ControlPannelWidthScale * windowSize.Height);
+ controlPannelSize = new Vector2(windowSize.Width - SceneViewPadding.X * 2.0f, ControlPannelWidthScale * windowSize.Height);
+ controlPannelPosition = new Vector2(SceneViewPadding.X, SceneViewPadding.Y);
+ }
+
+ // Update SceneView and ControlPannel size/position if we has.
+ if (avatarScene != null && circleView != null)
+ {
+ avatarScene.SizeWidth = sceneViewSize.Width;
+ avatarScene.SizeHeight = sceneViewSize.Height;
+ avatarScene.PositionX = 0;//sceneViewPosition.X;
+ avatarScene.PositionY = 0;//sceneViewPosition.Y;
+
+ circleView.SizeWidth = sceneViewSize.Width;
+ circleView.SizeHeight = sceneViewSize.Width;
+ circleView.PositionX = sceneViewPosition.X;
+ circleView.PositionY = sceneViewPosition.Y;
+ }
+
+ if (controlPannel != null)
+ {
+ controlPannel.SizeWidth = controlPannelSize.Width;
+ controlPannel.SizeHeight = controlPannelSize.Height;
+ controlPannel.PositionX = controlPannelPosition.X;
+ controlPannel.PositionY = controlPannelPosition.Y;
+ }
+ }
+
+ private void InitializeButtonStyle()
+ {
+ buttonStyle = new ButtonStyle()
+ {
+ Size = new Size(252, 48),
+ ItemSpacing = new Size2D(8, 8),
+ CornerRadius = 12.0f,
+ ItemHorizontalAlignment = HorizontalAlignment.Center,
+ ItemVerticalAlignment = VerticalAlignment.Center,
+ BorderlineWidth = 5.0f,
+ BackgroundColor = new Selector<Color>()
+ {
+ Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+ Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR1,
+ Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+ Selected = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR1,
+ Disabled = new Color(0.792f, 0.792f, 0.792f, 1),
+ },
+ BorderlineColorSelector = new Selector<Color>()
+ {
+ Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+ Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR2,
+ Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+ Selected = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR2,
+ Disabled = new Color(0.94f, 0.95f, 0.93f, 1.0f),
+ },
+ Text = new TextLabelStyle()
+ {
+ TextColor = new Color("#0D0D0D"),
+ PixelSize = 24,
+ },
+ };
+ }
+
+ private void InitializeSliderStyle()
+ {
+ sliderStyle = new SliderStyle()
+ {
+ Size = new Size(850, 50),
+ TrackThickness = 8,
+ Track = new ImageViewStyle()
+ {
+ Size = new Size(800, 8),
+ CornerRadius = 4.0f,
+ BackgroundColor = new Selector<Color>()
+ {
+ Normal = new Color(1.0f, 0.37f, 0.0f, 0.1f),
+ Disabled = new Color(1.0f, 0.37f, 0.0f, 0.1f),
+ },
+ },
+ Progress = new ImageViewStyle()
+ {
+ Size = new Size(800, 8),
+ CornerRadius = 4.0f,
+ BackgroundColor = new Selector<Color>()
+ {
+ //Normal = new Color("#FF6200"),
+ Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+ Disabled = new Color("#CACACA"),
+ },
+ },
+ Thumb = new ImageViewStyle()
+ {
+ Size = new Size(24, 24),
+ BackgroundColor = new Selector<Color>()
+ {
+ Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+ Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR1,
+ Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+ Disabled = new Color(0.94f, 0.95f, 0.93f, 1.0f),
+ },
+ BorderlineWidth = 5.0f,
+ BorderlineColorSelector = new Selector<Color>()
+ {
+ Normal = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR2,
+ Pressed = Styles.BIG_TAG_NORMAL_BACKGROUND_COLOR2,
+ Focused = Styles.BIG_TAG_FOCUS_BACKGROUND_COLOR1,
+ Disabled = new Color(0.94f, 0.95f, 0.93f, 1.0f),
+ },
+ CornerRadius = new Vector4(0.5f, 0.5f, 0.5f, 0.5f),
+ CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+ },
+ ValueIndicatorImage = new ImageViewStyle()
+ {
+ Size = new Size(43, 40),
+ BorderlineWidth = 1.0f,
+ BorderlineColor = new Color("#FF6200"),
+ BackgroundColor = new Color(1.0f, 1.0f, 1.0f, 0.0f),
+ CornerRadius = 12.0f,
+ },
+ ValueIndicatorText = new TextLabelStyle()
+ {
+ SizeHeight = 24,
+ PixelSize = 16,
+ TextColor = new Color("#FF6200"),
+ }
+ };
+ }
+
+ private void MakeControlPannelComponents()
+ {
+ AddControlEditor();
+ AddControlButton("ChangeAvatar", "button_avatar", mainScene.ChangeAvatar);
+ AddControlButton("Random Animation", "button_bvh", mainScene.StartRandomAnimation);
+ AddControlButton("EyeBlink", "button_bvh", mainScene.EyeBlink);
+
+ AddControlButton("TTS Init", "button_avatar", mainScene.InintTTsTest);
+ AddControlButton("TTS Start", "button_avatar", mainScene.StartTTSTest);
+ AddControlButton("TTS Stop", "button_avatar", mainScene.StopTTSTest);
+ AddControlButton("CZ", "button_avatar", mainScene.StartAvatarTalk_1);
+ AddControlButton("DK", "button_avatar", mainScene.StartAvatarTalk_2);
+ AddControlButton("GR", "button_avatar", mainScene.StartAvatarTalk_3);
+ AddControlButton("Start Mic", "button_bvh", mainScene.StartMic);
+ AddControlButton("Stop Mic", "button_bvh", mainScene.StopMic);
+ AddControlButton("Show/Hide", "button_bvh", mainScene.ShowHide);
+ AddControlSlider("Camera FOV", "slider_camera_fov", 0.1f, 1.3f, mainScene.GetSelectedCamera().FieldOfView.ConvertToFloat(), mainScene.SetupSceneViewCameraFov);
+ AddControlSlider("IBL intensity", "slider_ibl_factor", 0.1f, 0.8f, mainScene.IBLFactor, mainScene.SetupSceneViewIBLFactor);
+ AddControlButton("Quit", "button_quit", Exit);
+ }
+
+ private void AddControlEditor()
+ {
+ editor = new TextField()
+ {
+ Text = Utils.TTSText,
+ PlaceholderText = "Input Your Message",
+ Name = "InputText",
+ BackgroundColor = Color.White,
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ };
+ editor.TextChanged += (obj, e) => {
+ Utils.TTSText = e.TextField.Text;
+ };
+
+ controlPannel.Add(editor);
+ }
+
+ private void AddControlButton(string buttonText, string buttonName, Action func)
+ {
+ var button = new Button(buttonStyle)
+ {
+ Text = buttonText,
+ Name = buttonName,
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ };
+ button.Clicked += (o, e) =>
+ {
+ Button me = o as Button;
+ if (me == null) return;
+
+ func();
+ };
+
+ controlPannel.Add(button);
+ }
+
+ private Slider AddControlSlider(string sliderText, string sliderName, float minValue, float maxValue, float currentValue, Action<float> func)
+ {
+ var dummy = new View()
+ {
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ Layout = new LinearLayout()
+ {
+ LinearOrientation = LinearLayout.Orientation.Horizontal,
+ HorizontalAlignment = HorizontalAlignment.Begin,
+ VerticalAlignment = VerticalAlignment.Center,
+ CellPadding = new Size2D(5, 0),
+ },
+ };
+ var label = new TextLabel()
+ {
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ Text = sliderText,
+ FontSizeScale = 0.5f,
+ Focusable = false,
+ Weight = 0.2f,
+ MultiLine = true,
+ };
+ dummy.Add(label);
+ var slider = new Slider(sliderStyle)
+ {
+ WidthSpecification = LayoutParamPolicies.MatchParent,
+ MinValue = minValue,
+ MaxValue = maxValue,
+ CurrentValue = currentValue,
+ Name = sliderName,
+ Weight = 0.8f,
+ };
+ slider.ValueChanged += (o, e) =>
+ {
+ func(e.CurrentValue);
+ };
+ dummy.Add(slider);
+ controlPannel.Add(dummy);
+
+ return slider;
+ }
+
+ private void Exit()
+ {
+ OnExitButtonClicked?.Invoke(null, null);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2023 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 Tizen.AIAvatar;
+using Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.Security;
+
+using Tizen;
+using Tizen.Multimedia;
+
+namespace AIAvatar
+{
+ partial class Program : NUIApplication
+ {
+ private Window window;
+ private Tizen.NUI.Size windowSize;
+ private AvatarScene avatarScene;
+ private View circleMaskView;
+
+ private UIControlPanel uiControlPanel;
+
+ protected override void OnCreate()
+ {
+ base.OnCreate();
+ Initialize();
+ }
+
+ private void Initialize()
+ {
+ //var asyncAudioCapture = new AsyncAudioCapture(24000, AudioChannel.Mono, AudioSampleType.S16Le);
+
+ window = NUIApplication.GetDefaultWindow();
+ window.BackgroundColor = new Color(0.85f, 0.85f, 0.85f, 1.0f); ;
+
+ window.AddAvailableOrientation(Window.WindowOrientation.Landscape);
+ window.AddAvailableOrientation(Window.WindowOrientation.Portrait);
+ window.AddAvailableOrientation(Window.WindowOrientation.LandscapeInverse);
+ window.AddAvailableOrientation(Window.WindowOrientation.PortraitInverse);
+
+ window.Resized += OnResizedEvent;
+ window.KeyEvent += OnKeyEvent;
+
+ MakeBackground();
+ MakeAvatarScene();
+ MakeUIPanel();
+
+ RecalculatePositionSizeFromWindowSize();
+ }
+
+ private void OnResizedEvent(object sender, Window.ResizedEventArgs e)
+ {
+ RecalculatePositionSizeFromWindowSize();
+ }
+
+ private void MakeBackground()
+ {
+ var backgroundView = new View()
+ {
+ WidthResizePolicy = ResizePolicyType.FillToParent,
+ HeightResizePolicy = ResizePolicyType.FillToParent,
+ BackgroundImage = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/UI_BG.png",
+ };
+ backgroundView.TouchEvent += (o, e) =>
+ {
+ if (e.Touch.GetState(0) == PointStateType.Down)
+ {
+ Tizen.Log.Error("NUI", $"Background touched.\n");
+ }
+ return true;
+ };
+ window.Add(backgroundView);
+ }
+
+ private void MakeAvatarScene()
+ {
+ avatarScene = new AvatarScene();
+ avatarScene.UseFramebuffer = true;
+
+ avatarScene.SetAlphaMaskUrl(Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/contact-cards-mask.png");
+ avatarScene.EnableCropToMask(false);
+ //window.Add(avatarScene);
+
+ circleMaskView = new View()
+ {
+ Size = new Tizen.NUI.Size(),
+ Position = new Position(0, 0),
+ BackgroundColor = new Tizen.NUI.Color(0.0f, 0.0f, 0.0f, 0.0f),//new Tizen.NUI.Color("#221F1F"),
+ };
+ window.Add(circleMaskView);
+ circleMaskView.Add(avatarScene);
+
+ //circleMaskView.ClippingMode = ClippingModeType.ClipChildren;
+ //circleMaskView.CornerRadius = new Vector4(0.5f,0.5f,0.5f,0.5f);
+ circleMaskView.CornerRadiusPolicy = VisualTransformPolicyType.Relative;
+ }
+
+ private void MakeUIPanel()
+ {
+ uiControlPanel = new UIControlPanel();
+ uiControlPanel.OnExitButtonClicked += OnExitButtonClicked;
+ uiControlPanel.MakeControlPannel(window, avatarScene);
+ }
+
+ private void OnExitButtonClicked(object sender, EventArgs e)
+ {
+ ExitApplication();
+ }
+
+ private void RecalculatePositionSizeFromWindowSize()
+ {
+ uiControlPanel.ReizeUIPanel(avatarScene, circleMaskView);
+ }
+
+ private void OnKeyEvent(object sender, Window.KeyEventArgs e)
+ {
+
+ if (e.Key.State != Key.StateType.Down)
+ {
+ return;
+ }
+
+ if (e.Key.KeyPressedName == "Escape" || e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "BackSpace")
+ {
+ ExitApplication();
+ }
+ }
+
+ private void ExitApplication()
+ {
+ Utils.FullGC();
+ Exit();
+ }
+
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ app.Run(args);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright(c) 2023 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 Tizen.NUI;
+
+namespace AIAvatar
+{
+ public static class Styles
+ {
+ public static readonly Color BIG_TAG_NORMAL_BACKGROUND_COLOR1 = new Color(0xFF / 255.0f, 0xFE / 255.0f, 0xFE / 255.0f, 0.8f);
+ public static readonly Color BIG_TAG_NORMAL_BACKGROUND_COLOR2 = new Color(0xDB / 255.0f, 0xE3 / 255.0f, 0xFF / 255.0f, 0.8f);
+ public static readonly Color BIG_TAG_FOCUS_BACKGROUND_COLOR1 = new Color(0xD9 / 255.0f, 0xE1 / 255.0f, 0xFF / 255.0f, 0.8f);
+ public static readonly Color BIG_TAG_FOCUS_BACKGROUND_COLOR2 = new Color(0xB2 / 255.0f, 0xC4 / 255.0f, 0xFF / 255.0f, 0.8f);
+ public static readonly Color BIG_TAG_NORMAL_SHADOW_COLOR = new Color(62.0f / 255.0f, 62.0f / 255.0f, 62.0f / 255.0f, 0.8f);
+ }
+}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AIAvatar
+{
+ public static class Utils
+ {
+ static public string LogTag = "AvatarSample";
+ static public string TTSText = "Select an avatar that will guide you through the functions of your age.";
+ static public string ResourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+ static public void FullGC()
+ {
+ global::System.GC.Collect();
+ global::System.GC.WaitForPendingFinalizers();
+ global::System.GC.Collect();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="7.0" package="AIAvatarSample" version="1.0.0">
+ <profile name="common" />
+ <ui-application appid="AIAvatar.Sample"
+ exec="AIAvatarSample.dll"
+ type="dotnet"
+ multiple="false"
+ taskmanage="true"
+ nodisplay="false"
+ launch_mode="single"
+ api-version="10">
+ <label>Tizen.AIAvatar</label>
+ <icon>Tizen.AIAvatar.png</icon>
+ <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+ </ui-application>
+ <privileges>
+ <privilege>http://tizen.org/privilege/internet</privilege>
+ <privilege>http://tizen.org/privilege/window.priority.set</privilege>
+ <privilege>http://tizen.org/privilege/filesystem.read</privilege>
+ <privilege>http://tizen.org/privilege/recorder</privilege>
+ </privileges>
+</manifest>
--- /dev/null
+using System.Net.Mime;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Samples
+{
+ public class VisualTest : IExample
+ {
+ Window window = null;
+
+ static private string DEMO_IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "images/";
+
+ static private readonly string focusIndicatorImageUrl = DEMO_IMAGE_DIR + "i_focus_stroke_tile_2unit.9.webp";
+ static private readonly string[] ImageUrlList = {
+ DEMO_IMAGE_DIR + "Dali/DaliDemo/application-icon-1.png",
+ DEMO_IMAGE_DIR + "Dali/DaliDemo/application-icon-6.png",
+ DEMO_IMAGE_DIR + "Dali/DaliDemo/Kid1.svg",
+ DEMO_IMAGE_DIR + "Dali/ContactCard/gallery-small-2.jpg",
+ };
+
+ const float viewSizeWidth = 320.0f;
+ const float viewSizeHeight = 280.0f;
+ const float thumbnailAreaHeight = 96.0f;
+ const float thumbnailSize = 72.0f;
+ const float viewGap = 24.0f;
+
+ View rootView;
+
+ View[] visualViewList = new View[4];
+
+ Visuals.NPatchVisual focusIndicatorVisual;
+ Visuals.ColorVisual shadowVisual1;
+ Visuals.ColorVisual shadowVisual2;
+
+ public void Activate()
+ {
+ FocusManager.Instance.EnableDefaultAlgorithm(true);
+
+ // To use custom indicator, in this sample, removed default indicator
+ FocusManager.Instance.FocusIndicator = null;
+
+ window = NUIApplication.GetDefaultWindow();
+
+ CreateFocusedVisuals();
+
+ CreateLayoutViews();
+
+ window.KeyEvent += WinKeyEvent;
+ }
+
+ private void WinKeyEvent(object sender, Window.KeyEventArgs e)
+ {
+ if (e.Key.State == Key.StateType.Down)
+ {
+ if (e.Key.KeyPressedName == "1")
+ {
+ Tizen.Log.Error("NUI", $"Reset scene\n");
+
+ rootView?.Unparent();
+ rootView?.Dispose();
+
+ focusIndicatorVisual?.Dispose();
+ shadowVisual1?.Dispose();
+ shadowVisual2?.Dispose();
+
+ CreateFocusedVisuals();
+
+ CreateLayoutViews();
+ }
+ else if(e.Key.KeyPressedName == "2")
+ {
+ Tizen.Log.Error("NUI", $"GC test\n");
+ FullGC();
+ }
+ else if(e.Key.KeyPressedName == "3")
+ {
+ View focusedView = FocusManager.Instance.GetCurrentFocusView();
+ if(focusedView != null)
+ {
+ float tmp = focusedView.SizeWidth;
+ focusedView.SizeWidth = focusedView.SizeHeight * 2.0f;
+ focusedView.SizeHeight = tmp / 2.0f;
+ }
+ }
+ else if(e.Key.KeyPressedName == "4")
+ {
+ focusIndicatorVisual.ResourceUrl = null;
+ }
+ else if(e.Key.KeyPressedName == "5")
+ {
+ focusIndicatorVisual.ResourceUrl = focusIndicatorImageUrl;
+ }
+ }
+ }
+
+ public void Deactivate()
+ {
+ window.KeyEvent -= WinKeyEvent;
+
+ FocusManager.Instance.EnableDefaultAlgorithm(false);
+ rootView?.Unparent();
+ rootView?.Dispose();
+
+ focusIndicatorVisual?.Dispose();
+ shadowVisual1?.Dispose();
+ shadowVisual2?.Dispose();
+ }
+
+ private void FullGC()
+ {
+ global::System.GC.Collect();
+ global::System.GC.WaitForPendingFinalizers();
+ global::System.GC.Collect();
+ }
+
+ private void CreateFocusedVisuals()
+ {
+ focusIndicatorVisual = new Visuals.NPatchVisual()
+ {
+ Name = "indicator",
+
+ ResourceUrl = focusIndicatorImageUrl,
+
+ Origin = Visual.AlignType.Center,
+ PivotPoint = Visual.AlignType.Center,
+
+ Width = 1.01f,
+ Height = 1.01f,
+
+ BorderOnly = true,
+ };
+ shadowVisual1 = new Visuals.ColorVisual()
+ {
+ Name = "shadow1",
+
+ Color = new Color(0.0f, 0.0f, 0.0f, 0.2f),
+
+ CornerRadius = new Vector4(16.0f, 16.0f, 16.0f, 16.0f),
+
+ OffsetX = 2.0f,
+ OffsetY = 5.0f,
+ Width = 1.03f,
+ Height = 1.01f,
+
+ OffsetXPolicy = VisualTransformPolicyType.Absolute,
+ OffsetYPolicy = VisualTransformPolicyType.Absolute,
+ };
+ shadowVisual2 = new Visuals.ColorVisual()
+ {
+ Name = "shadow2",
+
+ Color = new Color(0.0f, 0.0f, 0.0f, 0.3f),
+
+ CornerRadius = new Vector4(16.0f, 16.0f, 16.0f, 16.0f),
+
+ OffsetX = 2.0f,
+ OffsetY = 5.0f,
+ Width = 1.01f,
+ Height = 1.0f,
+
+ OffsetXPolicy = VisualTransformPolicyType.Absolute,
+ OffsetYPolicy = VisualTransformPolicyType.Absolute,
+ };
+ }
+
+ private void CreateLayoutViews()
+ {
+ rootView = new View()
+ {
+ Name = "rootView",
+ BackgroundColor = new Color("#7c9df0"),
+
+ WidthResizePolicy = ResizePolicyType.FillToParent,
+ HeightResizePolicy = ResizePolicyType.FillToParent,
+ };
+
+ for(int i=0; i<4; i++)
+ {
+ visualViewList[i] = CreateViewWithVisual(i);
+ rootView.Add(visualViewList[i]);
+ }
+
+ window.Add(rootView);
+ }
+
+ private View CreateViewWithVisual(int id)
+ {
+ View view = new View()
+ {
+ Name = $"ID{id}",
+
+ SizeWidth = viewSizeWidth,
+ SizeHeight = viewSizeHeight,
+ PositionX = viewGap + (id % 2) * (viewSizeWidth + viewGap),
+ PositionY = viewGap + (id / 2) * (viewSizeHeight + viewGap),
+
+ Focusable = true,
+ FocusableInTouch = true,
+ KeyInputFocus = true,
+
+ Padding = new Extents(10, 10, 10, (ushort)thumbnailAreaHeight),
+ };
+
+ Visuals.ColorVisual backgroundVisual = new Visuals.ColorVisual()
+ {
+ Name = "background",
+
+ Color = Color.Gray,
+
+ CornerRadius = new Vector4(16.0f, 16.0f, 16.0f, 16.0f),
+ };
+
+ Visuals.ImageVisual imageVisual = new Visuals.ImageVisual()
+ {
+ Name = "mainImage",
+
+ ResourceUrl = ImageUrlList[id % 4],
+
+ CornerRadius = new Vector4(16.0f, 16.0f, 0.0f, 0.0f),
+
+ FittingMode = VisualFittingModeType.FitKeepAspectRatio,
+ };
+
+ Visuals.ColorVisual foregroundVisual = new Visuals.ColorVisual()
+ {
+ Name = "foreground",
+
+ Color = Color.LightSlateGray,
+ Opacity = 0.5f,
+
+ CornerRadius = new Vector4(0.0f, 0.0f, 16.0f, 16.0f),
+
+ Origin = Visual.AlignType.BottomBegin,
+ PivotPoint = Visual.AlignType.BottomBegin,
+
+ Height = thumbnailAreaHeight,
+
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ };
+
+ Visuals.TextVisual textVisual = new Visuals.TextVisual()
+ {
+ Name = "text",
+
+ Text = $"View {id} long text long long long long looooong",
+ TextColor = Color.White,
+ PointSize = 20.0f,
+
+ Origin = Visual.AlignType.BottomBegin,
+ PivotPoint = Visual.AlignType.BottomBegin,
+
+ HorizontalAlignment = HorizontalAlignment.Begin,
+ VerticalAlignment = VerticalAlignment.Center,
+
+ OffsetX = thumbnailAreaHeight,
+ OffsetY = -thumbnailAreaHeight * 0.4f,
+ Width = viewSizeWidth - thumbnailAreaHeight,
+ Height = thumbnailAreaHeight * 0.6f,
+
+ OffsetXPolicy = VisualTransformPolicyType.Absolute,
+ OffsetYPolicy = VisualTransformPolicyType.Absolute,
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ };
+
+ Visuals.AdvancedTextVisual subTextVisual = new Visuals.AdvancedTextVisual()
+ {
+ Name = "subtext",
+
+ Text = "subtext",
+ TextColor = Color.White,
+ PointSize = 12.0f,
+
+ Origin = Visual.AlignType.BottomBegin,
+ PivotPoint = Visual.AlignType.BottomBegin,
+
+ HorizontalAlignment = HorizontalAlignment.Begin,
+ VerticalAlignment = VerticalAlignment.Center,
+
+ OffsetX = thumbnailAreaHeight,
+ Width = viewSizeWidth - thumbnailAreaHeight,
+ Height = thumbnailAreaHeight * 0.4f,
+
+ OffsetXPolicy = VisualTransformPolicyType.Absolute,
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ };
+
+ try
+ {
+ subTextVisual.TranslatableText = "SID_OK";
+ }
+ catch(global::System.Exception e)
+ {
+ subTextVisual.Text = e.Message;
+ }
+
+ Visuals.ImageVisual thumbnailVisual = new Visuals.ImageVisual()
+ {
+ Name = "thumbnailImage",
+
+ ResourceUrl = ImageUrlList[id % 4],
+
+ CornerRadius = new Vector4(8.0f, 8.0f, 8.0f, 8.0f),
+
+ Origin = Visual.AlignType.BottomBegin,
+ PivotPoint = Visual.AlignType.Center,
+
+ OffsetX = thumbnailAreaHeight / 2.0f,
+ OffsetY = -thumbnailAreaHeight / 2.0f,
+
+ Width = thumbnailSize,
+ Height = thumbnailSize,
+
+ DesiredWidth = (int)thumbnailSize,
+ DesiredHeight = (int)thumbnailSize,
+
+ OffsetXPolicy = VisualTransformPolicyType.Absolute,
+ OffsetYPolicy = VisualTransformPolicyType.Absolute,
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ };
+
+ view.AddVisual(backgroundVisual);
+ view.AddVisual(imageVisual);
+ view.AddVisual(foregroundVisual);
+ view.AddVisual(textVisual);
+ view.AddVisual(subTextVisual);
+ view.AddVisual(thumbnailVisual);
+
+ view.FocusGained += (s, e) =>
+ {
+ View me = s as View;
+ if(me != null)
+ {
+ Tizen.Log.Error("NUI", $"View {me.ID} focus gained.\n");
+
+ me.AddVisual(focusIndicatorVisual);
+ me.AddVisual(shadowVisual1);
+ me.AddVisual(shadowVisual2);
+
+ focusIndicatorVisual.RaiseToTop();
+ shadowVisual1.LowerToBottom();
+ shadowVisual2.LowerBelow(shadowVisual1);
+
+ var visual = me.FindVisualByName("foreground");
+ visual.Color = Color.LightGray;
+ visual.Opacity = 0.5f;
+
+ //visual = me.FindVisualByName("background");
+ visual = me.GetVisualAt(2u); // Should be background
+ visual.Color = Color.White;
+
+ var textVisual = me.FindVisualByName("text") as Visuals.TextVisual;
+ textVisual.TextColor = Color.Black;
+ textVisual = me.FindVisualByName("subtext") as Visuals.TextVisual;
+ textVisual.TextColor = Color.Black;
+ }
+ };
+
+ view.FocusLost += (s, e) =>
+ {
+ View me = s as View;
+ if(me != null)
+ {
+ Tizen.Log.Error("NUI", $"View {me.ID} focus losted.\n");
+
+ me.RemoveVisual(focusIndicatorVisual);
+ me.RemoveVisual(shadowVisual1);
+ me.RemoveVisual(shadowVisual2);
+
+ var visual = me.FindVisualByName("foreground");
+ visual.Color = Color.LightSlateGray;
+ visual.Opacity = 0.5f;
+
+ //visual = me.FindVisualByName("background");
+ visual = me.GetVisualAt(0u); // Should be background
+ visual.Color = Color.Gray;
+
+ var textVisual = me.FindVisualByName("text") as Visuals.TextVisual;
+ textVisual.TextColor = Color.White;
+ textVisual = me.FindVisualByName("subtext") as Visuals.TextVisual;
+ textVisual.TextColor = Color.White;
+ }
+ };
+
+ view.TouchEvent += (o, e) =>
+ {
+ return true;
+ };
+
+ return view;
+ }
+ }
+}
--- /dev/null
+{
+ "folders": [
+ {
+ "path": "."
+ },
+ {
+ "path": "../../src/Tizen.NUI"
+ },
+ {
+ "path": "../../src/Tizen.NUI.Components"
+ }
+ ],
+ "settings": {}
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net6.0</TargetFramework>
+ <AssemblyName>VisualTest</AssemblyName>
+ </PropertyGroup>
+
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugType>portable</DebugType>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>None</DebugType>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Tizen.NET.Sdk" Version="1.0.9" />
+ <ProjectReference Include="../../src/Tizen/Tizen.csproj" />
+ <ProjectReference Include="../../src/Tizen.NUI/Tizen.NUI.csproj" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <NeedInjection>True</NeedInjection>
+ </PropertyGroup>
+</Project>
--- /dev/null
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.33214.272
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.VisualTest", "Tizen.NUI.VisualTest.csproj", "{3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen", "..\..\src\Tizen\Tizen.csproj", "{F4ADAF15-01AA-477E-A85A-BEB297E6B07E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.Common", "..\..\src\Tizen.Applications.Common\Tizen.Applications.Common.csproj", "{0B96B17C-DACA-4745-88B1-6CFC1825A510}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ComponentBased", "..\..\src\Tizen.Applications.ComponentBased\Tizen.Applications.ComponentBased.csproj", "{E117D074-C23D-41FD-A77D-2E9E6FF85676}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ThemeManager", "..\..\src\Tizen.Applications.ThemeManager\Tizen.Applications.ThemeManager.csproj", "{FB8B42D6-76CC-4836-8A80-58A816C6A17F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.SystemSettings", "..\..\src\Tizen.System.SystemSettings\Tizen.System.SystemSettings.csproj", "{EC28F259-C790-4FA3-A834-00795E2A7E2F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.Information", "..\..\src\Tizen.System.Information\Tizen.System.Information.csproj", "{02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.System.Feedback", "..\..\src\Tizen.System.Feedback\Tizen.System.Feedback.csproj", "{D422D03E-7E32-4230-8306-B16DFE27E95A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Tracer", "..\..\src\Tizen.Tracer\Tizen.Tracer.csproj", "{A0AA9346-2025-4803-A168-3B39A367BB92}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Log", "..\..\src\Tizen.Log\Tizen.Log.csproj", "{1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI", "..\..\src\Tizen.NUI\Tizen.NUI.csproj", "{29B426DA-FFDE-49D2-BD73-FE155F9502E8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Components", "..\..\src\Tizen.NUI.Components\Tizen.NUI.Components.csproj", "{2A669CBF-DFA8-4EA3-852D-3137493DE884}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C6CE4CE-9D35-42C9-B23D-BBFFA96B3955}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F4ADAF15-01AA-477E-A85A-BEB297E6B07E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0B96B17C-DACA-4745-88B1-6CFC1825A510}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E117D074-C23D-41FD-A77D-2E9E6FF85676}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EC28F259-C790-4FA3-A834-00795E2A7E2F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {02BEE3AD-99A6-44A5-89FC-D9F4132D9ECE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D422D03E-7E32-4230-8306-B16DFE27E95A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D422D03E-7E32-4230-8306-B16DFE27E95A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D422D03E-7E32-4230-8306-B16DFE27E95A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D422D03E-7E32-4230-8306-B16DFE27E95A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A0AA9346-2025-4803-A168-3B39A367BB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A0AA9346-2025-4803-A168-3B39A367BB92}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A0AA9346-2025-4803-A168-3B39A367BB92}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A0AA9346-2025-4803-A168-3B39A367BB92}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1E8250DB-92C3-44A5-8D57-3CFDE0C0021D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {29B426DA-FFDE-49D2-BD73-FE155F9502E8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A669CBF-DFA8-4EA3-852D-3137493DE884}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {355D568D-D02A-490A-A6AC-FD6C7D97457A}
+ EndGlobalSection
+EndGlobal
--- /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 Tizen.NUI;
+using Tizen.NUI.BaseComponents;
+using Tizen.NUI.Constants;
+
+class VisualTestExample : NUIApplication
+{
+ const uint VIEW_COUNT = 1000;
+
+ static string IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "image/";
+ readonly static string[] IMAGE_PATH =
+ {
+ IMAGE_DIR + "gallery-small-1.jpg",
+ };
+
+ Window mWindow;
+ Vector2 mWindowSize;
+ float mViewSize;
+
+ TextLabel infoLabel;
+
+ View rootView;
+
+ ImageView dummyView;
+ Animation dummyAnimation;
+
+ int state = 0;
+
+ private global::System.Random mRandom = new global::System.Random();
+
+ protected void CreateScene()
+ {
+ mWindow = Window.Instance;
+ mWindow.BackgroundColor = Color.White;
+ mWindowSize = mWindow.WindowSize;
+
+ mViewSize = global::System.Math.Min(mWindowSize.X, mWindowSize.Y) / 10.0f;
+
+ infoLabel = new TextLabel(
+ $"VisualObject Test with {VIEW_COUNT} and 2 children. (ImageView + TextLabel)\n" +
+ $"Press 1 key to start test with View. (ImageView + TextLabel)\n" +
+ $"Press 2 key to start test with Visual. (ImageVisual + TextLabel)\n" +
+ $"Press 3 key to start test with various Visuals. (ColorVisual + ImageVisual + TextVisual + BorderVisual)\n" +
+ $"Press 4 key to animate the size of View.\n" +
+ $"(View size : {mViewSize})\n")
+ {
+ MultiLine = true,
+ PointSize = 20.0f,
+ };
+
+ // For image cache.
+ dummyView = new ImageView()
+ {
+ ResourceUrl = IMAGE_PATH[0],
+ SizeWidth = 1.0f,
+ SizeHeight = 1.0f,
+ };
+
+ // For keep rendering forever
+ dummyAnimation = new Animation(1000);
+ dummyAnimation.AnimateTo(dummyView, "PositionX", 1.0f);
+ dummyAnimation.Looping = true;
+ dummyAnimation.Play();
+
+ rootView = new View()
+ {
+ SizeWidth = mWindowSize.X,
+ SizeHeight = mWindowSize.Y,
+ BackgroundColor = Color.White,
+ };
+ mWindow.Add(dummyView);
+ mWindow.Add(rootView);
+
+ mWindow.GetOverlayLayer().Add(infoLabel);
+
+ mWindow.KeyEvent += OnKeyEvent;
+ }
+
+ void NormalViewTest()
+ {
+ global::System.DateTime startTime;
+ global::System.DateTime endTime;
+
+ startTime = global::System.DateTime.Now;
+
+ for(int i = 0; i < VIEW_COUNT; i++)
+ {
+ View view = new View()
+ {
+ SizeWidth = mViewSize,
+ SizeHeight = mViewSize,
+ PositionX = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.X - mViewSize),
+ PositionY = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.Y - mViewSize),
+ };
+ CreateNormalView(ref view);
+ rootView.Add(view);
+ }
+
+ endTime = global::System.DateTime.Now;
+
+ Tizen.Log.Error("NUI.Visuals", $"NormalViewTest : {(endTime - startTime).TotalMilliseconds} ms\n");
+ }
+
+ void VisualViewTest()
+ {
+ global::System.DateTime startTime;
+ global::System.DateTime endTime;
+
+ startTime = global::System.DateTime.Now;
+
+ for(int i = 0; i < VIEW_COUNT; i++)
+ {
+ View view = new View()
+ {
+ SizeWidth = mViewSize,
+ SizeHeight = mViewSize,
+ PositionX = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.X - mViewSize),
+ PositionY = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.Y - mViewSize),
+ };
+ CreateVisualView(ref view);
+ rootView.Add(view);
+ }
+
+ endTime = global::System.DateTime.Now;
+
+ Tizen.Log.Error("NUI.Visuals", $"VisualViewTest : {(endTime - startTime).TotalMilliseconds} ms\n");
+ }
+
+ void GeneralVisualTest()
+ {
+ global::System.DateTime startTime;
+ global::System.DateTime endTime;
+
+ startTime = global::System.DateTime.Now;
+
+ for(int i = 0; i < VIEW_COUNT; i++)
+ {
+ View view = new View()
+ {
+ SizeWidth = mViewSize,
+ SizeHeight = mViewSize,
+ PositionX = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.X - mViewSize),
+ PositionY = (mRandom.Next()%1000 / 999.0f) * (mWindowSize.Y - mViewSize),
+ };
+ CreateGeneralVisualView(ref view);
+ rootView.Add(view);
+ }
+
+ endTime = global::System.DateTime.Now;
+
+ Tizen.Log.Error("NUI.Visuals", $"GeneralVisualTest : {(endTime - startTime).TotalMilliseconds} ms\n");
+ }
+
+
+ void OnKeyEvent(object source, Window.KeyEventArgs e)
+ {
+ if (e.Key.State == Key.StateType.Down)
+ {
+ switch(e.Key.KeyPressedName)
+ {
+ case "Escape":
+ case "Back":
+ case "XF86Back":
+ {
+ if(state == 0)
+ {
+ Deactivate();
+ Exit();
+ }
+ else
+ {
+ state = 0;
+ viewWidthChangeAnimation?.Stop();
+ viewWidthChangeAnimation?.Clear();
+ viewWidthChangeAnimation?.Dispose();
+ viewWidthChangeAnimation = null;
+
+ rootView?.Unparent();
+ rootView?.DisposeRecursively();
+ rootView = new View()
+ {
+ SizeWidth = mWindowSize.X,
+ SizeHeight = mWindowSize.Y,
+ BackgroundColor = Color.White,
+ };
+ mWindow.Add(rootView);
+ FullGC();
+ FullGC();
+ }
+ break;
+ }
+ case "1":
+ {
+ if(state == 0)
+ {
+ state = 1;
+ NormalViewTest();
+ }
+ break;
+ }
+ case "2":
+ {
+ if(state == 0)
+ {
+ state = 2;
+ VisualViewTest();
+ }
+ break;
+ }
+ case "3":
+ {
+ if(state == 0)
+ {
+ state = 3;
+ GeneralVisualTest();
+ }
+ break;
+ }
+ case "4":
+ {
+ if(state != 0)
+ {
+ ViewSizeChangeTest();
+ }
+ break;
+ }
+ default:
+ {
+ FullGC();
+ FullGC();
+ break;
+ }
+ }
+ }
+ }
+
+ public void Activate()
+ {
+ CreateScene();
+ }
+ public void FullGC()
+ {
+ global::System.GC.Collect();
+ global::System.GC.WaitForPendingFinalizers();
+ global::System.GC.Collect();
+ }
+
+ public void Deactivate()
+ {
+ DestroyScene();
+ }
+
+ private void DestroyScene()
+ {
+ rootView?.Unparent();
+ rootView?.Dispose();
+ }
+
+ private Animation viewWidthChangeAnimation = null;
+ private void ViewSizeChangeTest()
+ {
+ viewWidthChangeAnimation?.Stop();
+ viewWidthChangeAnimation?.Clear();
+ viewWidthChangeAnimation?.Dispose();
+ viewWidthChangeAnimation = new Animation(3000);
+ for(int i = 0; i < VIEW_COUNT; i++)
+ {
+ View view = rootView.GetChildAt((uint)i);
+
+ if(view == null)break;
+
+ viewWidthChangeAnimation.AnimateTo(view, "SizeWidth", mViewSize * 2.0f, 0, 1000);
+ viewWidthChangeAnimation.AnimateTo(view, "SizeWidth", mViewSize * 0.0f, 1000, 2000);
+ viewWidthChangeAnimation.AnimateTo(view, "SizeWidth", mViewSize * 1.0f, 2000, 3000);
+ }
+
+ viewWidthChangeAnimation.Play();
+ }
+
+ private void CreateNormalView(ref View view)
+ {
+ // ImageView with corner radius top.
+ ImageView imageView = new ImageView()
+ {
+ ResourceUrl = IMAGE_PATH[0],
+ CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+ CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+
+ SizeWidth = mViewSize,
+ SizeHeight = mViewSize,
+ };
+
+ TextLabel textLabel = new TextLabel()
+ {
+ Text = "1",
+ PointSize = 20.0f,
+
+ SizeWidth = mViewSize,
+ SizeHeight = mViewSize,
+
+ PositionY = mViewSize * 0.25f,
+ PositionX = mViewSize * 0.5f,
+
+ ParentOrigin = Position.ParentOriginCenter,
+ PivotPoint = Position.PivotPointCenter,
+ PositionUsesPivotPoint = true,
+ };
+
+ view.Add(imageView);
+ view.Add(textLabel);
+ }
+
+ private void CreateVisualView(ref View view)
+ {
+ // ImageView with corner radius top.
+ Tizen.NUI.Visuals.ImageVisual imageVisual = new Tizen.NUI.Visuals.ImageVisual()
+ {
+ ResourceUrl = IMAGE_PATH[0],
+ CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+ CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+
+ Width = mViewSize,
+ Height = mViewSize,
+
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ };
+
+ /*
+ Tizen.NUI.Visuals.TextVisual textVisual = new Tizen.NUI.Visuals.TextVisual()
+ {
+ Text = "1",
+ PointSize = 20.0f,
+
+ Width = mViewSize,
+ Height = mViewSize,
+
+ OffsetY = mViewSize * 0.25f,
+
+ Origin = Visual.AlignType.Center,
+ PivotPoint = Visual.AlignType.Center,
+
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ OffsetYPolicy = VisualTransformPolicyType.Absolute,
+ };
+ */
+
+ view.AddVisual(imageVisual);
+ //view.AddVisual(textVisual);
+
+ TextLabel textLabel = new TextLabel()
+ {
+ Text = "1",
+ PointSize = 20.0f,
+
+ SizeWidth = mViewSize,
+ SizeHeight = mViewSize,
+
+ PositionY = mViewSize * 0.25f,
+ PositionX = mViewSize * 0.5f,
+
+ ParentOrigin = Position.ParentOriginCenter,
+ PivotPoint = Position.PivotPointCenter,
+ PositionUsesPivotPoint = true,
+ };
+ view.Add(textLabel);
+ }
+
+ private void CreateGeneralVisualView(ref View view)
+ {
+ #region ColorVisual
+ Tizen.NUI.Visuals.ColorVisual colorVisual = new Tizen.NUI.Visuals.ColorVisual()
+ {
+ Color = new Color(1.0f, 0.0f, 0.0f, 0.9f),
+ CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+ CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+
+ Width = 1.1f,
+ Height = 1.1f,
+
+ BlurRadius = mViewSize * 0.05f,
+ OffsetX = 0.1f,
+ OffsetY = 0.05f,
+
+ ExtraWidth = mViewSize * 0.15f,
+ ExtraHeight = -mViewSize * 0.05f,
+ };
+ view.AddVisual(colorVisual);
+ #endregion
+
+ #region ImageVisual
+ Tizen.NUI.Visuals.ImageVisual imageVisual = new Tizen.NUI.Visuals.ImageVisual()
+ {
+ ResourceUrl = IMAGE_PATH[0],
+ CornerRadius = new Vector4(0.15f, 0.15f, 0.15f, 0.15f),
+ CornerRadiusPolicy = VisualTransformPolicyType.Relative,
+ BorderlineWidth = mViewSize * 0.05f,
+ BorderlineColor = Color.Green,
+ BorderlineOffset = 1.0f,
+
+ Width = mViewSize,
+ Height = mViewSize,
+
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ };
+ view.AddVisual(imageVisual);
+ #endregion
+
+ #region TextVisual
+ Tizen.NUI.Visuals.TextVisual textVisual = new Tizen.NUI.Visuals.TextVisual()
+ {
+ Text = "1",
+ PointSize = 20.0f,
+
+ Width = mViewSize,
+ Height = mViewSize,
+
+ OffsetY = mViewSize * 0.25f,
+
+ Origin = Visual.AlignType.Center,
+ PivotPoint = Visual.AlignType.Center,
+
+ WidthPolicy = VisualTransformPolicyType.Absolute,
+ HeightPolicy = VisualTransformPolicyType.Absolute,
+ OffsetYPolicy = VisualTransformPolicyType.Absolute,
+ };
+ view.AddVisual(textVisual);
+ #endregion
+
+ #region BorderVisual
+ Tizen.NUI.Visuals.BorderVisual borderVisual = new Tizen.NUI.Visuals.BorderVisual()
+ {
+ BorderColor = Color.Blue,
+ BorderWidth = mViewSize * 0.05f,
+ AntiAliasing = false, // For speed up
+ };
+ view.AddVisual(borderVisual);
+ #endregion
+ }
+
+ protected override void OnCreate()
+ {
+ // Up call to the Base class first
+ base.OnCreate();
+ Activate();
+ }
+
+ /// <summary>
+ /// The main entry point for the application.
+ /// </summary>
+ [global::System.STAThread] // Forces app to use one thread to access NUI
+ static void Main(string[] args)
+ {
+ VisualTestExample example = new VisualTestExample();
+ example.Run(args);
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="6" package="org.tizen.example.Tizen.NUI.VisualTest" version="1.0.0">
+ <profile name="common" />
+ <ui-application appid="org.tizen.example.Tizen.NUI.VisualTest"
+ exec="VisualTest.dll"
+ type="dotnet-nui"
+ multiple="false"
+ taskmanage="true"
+ nodisplay="false"
+ launch_mode="single"
+ >
+ <label>Tizen.NUI.VisualTest</label>
+ <icon>Tizen.NUI.VisualTest.png</icon>
+ <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+ </ui-application>
+</manifest>