// Copyright (c) 2021 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
using UnityEngine;
namespace Mediapipe.Unity
{
///
/// This class draws annotations on the screen which is the parent of the attached .
/// That is, it's used like this.
/// 1. Select a GameObject where you'd like to draw annotations.
/// 2. Create an empty child GameObject (let's say AnnotationLayer) directly under it.
/// 3. Attach to AnnotationLayer.
/// 4. Create an empty child GameObject (let's say RootAnnotation) directly under AnnotationLayer.
/// 5. Attach to RootAnnotation.
///
///
/// Note that this class can be accessed from a thread other than main thread.
/// Extended classes must be implemented to work in such a situation, since Unity APIs won't work in other threads.
///
public abstract class AnnotationController : MonoBehaviour where T : HierarchicalAnnotation
{
[SerializeField] protected T annotation;
protected bool isStale = false;
public bool isMirrored
{
get => annotation.isMirrored;
set
{
if (annotation.isMirrored != value)
{
annotation.isMirrored = value;
}
}
}
public RotationAngle rotationAngle
{
get => annotation.rotationAngle;
set
{
if (annotation.rotationAngle != value)
{
annotation.rotationAngle = value;
}
}
}
protected virtual void Start()
{
if (!TryGetComponent(out var _))
{
Logger.LogVerbose(GetType().Name, $"Adding RectTransform to {gameObject.name}");
var rectTransform = gameObject.AddComponent();
// stretch width and height by default
rectTransform.pivot = new Vector2(0.5f, 0.5f);
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.one;
rectTransform.anchoredPosition3D = Vector3.zero;
rectTransform.sizeDelta = Vector2.zero;
}
}
protected virtual void LateUpdate()
{
if (isStale)
{
SyncNow();
}
}
protected virtual void OnDestroy()
{
if (annotation != null)
{
Destroy(annotation);
annotation = null;
}
isStale = false;
}
///
/// Draw annotations in current thread.
/// This method must set to false.
///
///
/// This method can only be called from main thread.
///
protected abstract void SyncNow();
protected void UpdateCurrentTarget(TValue newTarget, ref TValue currentTarget)
{
if (IsTargetChanged(newTarget, currentTarget))
{
currentTarget = newTarget;
isStale = true;
}
}
protected bool IsTargetChanged(TValue newTarget, TValue currentTarget)
{
// It's assumed that target has not changed iff previous target and new target are both null.
return currentTarget != null || newTarget != null;
}
}
}