//================================================================================================================================
//
// Copyright (c) 2015-2021 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved.
// EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China
// and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd.
//
//================================================================================================================================
using System;
using System.Collections;
using UnityEngine;
namespace easyar
{
///
/// which controls in the scene, providing a few extensions in the Unity environment. Use directly when necessary.
/// 在场景中控制的,在Unity环境下提供功能扩展。如有需要可以直接使用。
///
public class ImageTargetController : TargetController
{
///
/// EasyAR Sense API. Accessible after TargetAvailable event.
/// EasyAR Sense API,可以在TargetAvailable event之后访问。
///
public ImageTarget Target { get; private set; }
///
/// Target data source.
/// Target数据来源。
///
public DataSource SourceType = DataSource.ImageFile;
///
/// Image data source for target creation. Valid when == .
/// 创建target的图像数据来源。在 == 的时候有效。
///
[HideInInspector, SerializeField]
public ImageFileSourceData ImageFileSource = new ImageFileSourceData();
///
/// Target data source for target creation. Valid when == .
/// 创建target的target data来源。在 == 的时候有效。
///
[HideInInspector, SerializeField]
public TargetDataFileSourceData TargetDataFileSource = new TargetDataFileSourceData();
///
/// Target source when using a target already created. Valid when == .
/// 直接使用创建好的target时的target来源。在 == 的时候有效。
///
public ImageTarget TargetSource;
#if UNITY_EDITOR
///
/// data storage.
/// 数据存储。
///
public GizmoStorage GizmoData = new GizmoStorage();
#endif
[HideInInspector, SerializeField]
private bool trackerHasSet;
[HideInInspector, SerializeField]
private ImageTrackerFrameFilter tracker;
private ImageTrackerFrameFilter loader;
private float scale = 0.1f;
private float scaleX = 0.1f;
private bool preHFlip;
///
/// Event when can be used.
/// 可以使用的事件。
///
public event Action TargetAvailable;
///
/// Target load finish event. The bool value indicates the load success or not.
/// Target加载完成的事件。bool值表示加载是否成功。
///
public event Action TargetLoad;
///
/// Target unload finish event. The bool value indicates the unload success or not.
/// Target卸载完成的事件。bool值表示卸载是否成功。
///
public event Action TargetUnload;
///
/// Target data source type.
/// Target数据来源类型。
///
public enum DataSource
{
///
/// Image file (*.jpg, *.png).
/// 图像文件(*.jpg, *.png)。
///
ImageFile,
///
/// Target data file (*.etd).
/// Target data文件(*.etd)。
///
TargetDataFile,
///
/// object.
/// 对象。
///
Target,
}
///
/// The which loads the target after . When set to null, the target will be unloaded from tracker previously set. Modify at any time and takes effect immediately.
/// 在之后加载target的。如果设为null,target将会被从之前设置的tracker中卸载。可随时修改,立即生效。
///
public ImageTrackerFrameFilter Tracker
{
get
{
return tracker;
}
set
{
tracker = value;
UpdateTargetInTracker();
}
}
///
/// Physical size of in meter.
/// 的物理大小,单位为米。
///
public Vector2 Size
{
get
{
if (Target == null)
{
return new Vector2();
}
return new Vector2(Target.scale(), Target.scale() / Target.aspectRatio());
}
private set { }
}
///
/// MonoBehaviour Start
///
protected override void Start()
{
base.Start();
if (!EasyARController.Initialized)
{
return;
}
switch (SourceType)
{
case DataSource.ImageFile:
LoadImageFile(new ImageFileSourceData()
{
PathType = ImageFileSource.PathType,
Path = ImageFileSource.Path,
Name = ImageFileSource.Name,
Scale = ImageFileSource.Scale
});
break;
case DataSource.TargetDataFile:
LoadTargetDataFile(new TargetDataFileSourceData()
{
PathType = TargetDataFileSource.PathType,
Path = TargetDataFileSource.Path
});
break;
case DataSource.Target:
LoadTarget(TargetSource);
break;
default:
break;
}
}
///
/// MonoBehaviour Update
///
protected virtual void Update()
{
CheckScale();
}
///
/// MonoBehaviour OnDestroy
///
protected virtual void OnDestroy()
{
if (tracker)
{
tracker = null;
UpdateTargetInTracker();
}
if (Target != null)
{
Target.Dispose();
Target = null;
}
}
protected override void OnTracking()
{
CheckScale();
}
private void LoadImageFile(ImageFileSourceData source)
{
EasyARController.Instance.StartCoroutine(FileUtil.LoadFile(source.Path, source.PathType, (Buffer buffer) =>
{
EasyARController.Instance.StartCoroutine(LoadImageBuffer(buffer.Clone(), source));
}));
}
private void LoadTargetDataFile(TargetDataFileSourceData source)
{
EasyARController.Instance.StartCoroutine(FileUtil.LoadFile(source.Path, source.PathType, (Buffer buffer) =>
{
EasyARController.Instance.StartCoroutine(LoadTargetDataBuffer(buffer.Clone()));
}));
}
private void LoadTarget(ImageTarget source)
{
Target = source;
if (Target != null && TargetAvailable != null)
{
TargetAvailable();
}
UpdateScale();
UpdateTargetInTracker();
}
private IEnumerator LoadImageBuffer(Buffer buffer, ImageFileSourceData source)
{
using (buffer)
{
Optional imageOptional = null;
bool taskFinished = false;
EasyARController.Instance.Worker.Run(() =>
{
imageOptional = ImageHelper.decode(buffer);
taskFinished = true;
});
while (!taskFinished)
{
yield return 0;
}
if (imageOptional.OnNone)
{
throw new Exception("invalid buffer");
}
using (var image = imageOptional.Value)
using (var param = new ImageTargetParameters())
{
param.setImage(image);
param.setName(source.Name);
param.setScale(source.Scale);
param.setUid(Guid.NewGuid().ToString());
param.setMeta(string.Empty);
var targetOptional = ImageTarget.createFromParameters(param);
if (targetOptional.OnSome)
{
Target = targetOptional.Value;
if (Target != null && TargetAvailable != null)
{
TargetAvailable();
}
}
else
{
throw new Exception("invalid parameter");
}
}
}
UpdateTargetInTracker();
}
private IEnumerator LoadTargetDataBuffer(Buffer buffer)
{
using (buffer)
{
Optional targetOptional = null;
bool taskFinished = false;
EasyARController.Instance.Worker.Run(() =>
{
targetOptional = ImageTarget.createFromTargetData(buffer);
taskFinished = true;
});
while (!taskFinished)
{
yield return 0;
}
if (targetOptional.OnSome)
{
Target = targetOptional.Value;
if (Target != null && TargetAvailable != null)
{
TargetAvailable();
}
}
else
{
throw new Exception("invalid buffer");
}
}
UpdateTargetInTracker();
}
private void UpdateTargetInTracker()
{
if (Target == null)
{
return;
}
if (loader && loader != tracker)
{
loader.UnloadImageTarget(this, (target, status) =>
{
if (TargetUnload != null)
{
TargetUnload(target, status);
}
if (status)
{
IsLoaded = false;
}
});
loader = null;
}
if (tracker && tracker != loader)
{
var trackerLoad = tracker;
tracker.LoadImageTarget(this, (target, status) =>
{
if (trackerLoad == tracker && !status)
{
loader = null;
}
UpdateScale();
if (TargetLoad != null)
{
TargetLoad(target, status);
}
IsLoaded = status;
});
loader = tracker;
}
}
private void UpdateScale()
{
if (Target == null)
return;
scale = Target.scale();
var vec3Unit = Vector3.one;
if (HorizontalFlip)
{
vec3Unit.x = -vec3Unit.x;
}
transform.localScale = vec3Unit * scale;
scaleX = transform.localScale.x;
preHFlip = HorizontalFlip;
}
private void CheckScale()
{
if (Target == null)
return;
if (scaleX != transform.localScale.x)
{
Target.setScale(Math.Abs(transform.localScale.x));
UpdateScale();
}
else if (scale != transform.localScale.y)
{
Target.setScale(Math.Abs(transform.localScale.y));
UpdateScale();
}
else if (scale != transform.localScale.z)
{
Target.setScale(Math.Abs(transform.localScale.z));
UpdateScale();
}
else if (scale != Target.scale())
{
UpdateScale();
}
else if (preHFlip != HorizontalFlip)
{
UpdateScale();
}
}
///
/// Image data for target creation.
/// 创建target的图像数据。
///
[Serializable]
public class ImageFileSourceData
{
///
/// File path type.
/// 文件路径类型。
///
public PathType PathType = PathType.StreamingAssets;
///
/// File path.
/// 文件路径。
///
public string Path = string.Empty;
///
/// Target name.
/// Target名字。
///
public string Name = string.Empty;
///
/// Target scale in meter. Reference .
/// Target图像的缩放比例,单位为米。参考。
///
public float Scale = 0.1f;
}
///
/// Target data for target creation. Target scale and name are defined in the etd file.
/// 创建target的target data。Target名字和缩放在etd文件中定义。
///
[Serializable]
public class TargetDataFileSourceData
{
///
/// File path type.
/// 文件路径类型。
///
public PathType PathType = PathType.StreamingAssets;
///
/// File path.
/// 文件路径。
///
public string Path = string.Empty;
}
#if UNITY_EDITOR
///
/// data. Used for gizmo display.
/// 数据,用于在编辑器中显示的gizmo。
///
public class GizmoStorage
{
public string Signature;
public Texture2D Texture;
public Material Material;
public float Scale = 0.1f;
public float ScaleX = 0.1f;
public bool HorizontalFlip;
}
#endif
}
}