/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR. */ using OmiLAXR.Components; using OmiLAXR.Components.Facial.Emotion; using UnityEngine; namespace OmiLAXR.TrackingBehaviours.Learner { public abstract class FacialTrackingBehaviour : ScheduledTrackingBehaviour { public struct EmotionChangedEvent { public EmotionLogic Emotion; // reference to the ScriptableObject public bool IsActive; // true = activated, false = deactivated public float Intensity; // intensity at time of change public FaceData FaceData; } [Gesture("Face"), Action("Data")] public TrackingBehaviourEvent OnDataUpdated = new TrackingBehaviourEvent(); [Gesture("Face"), Action("Emotion")] public TrackingBehaviourEvent OnEmotionChanged = new TrackingBehaviourEvent(); [SerializeField] private EmotionLogic[] emotions; public abstract bool IsAvailable { get; } public abstract bool IsEnabled { get; } protected abstract FaceData FetchFaceData(); public FaceData FaceData { get; private set; } private FaceData _lastFaceData; public bool detectOnChange = true; // A delegate that knows how to build the provider from FaceData protected void Reset() { scheduler = GetDefaultScheduler(); emotions = new EmotionLogic[] { ScriptableObject.CreateInstance(), ScriptableObject.CreateInstance(), ScriptableObject.CreateInstance(), ScriptableObject.CreateInstance(), ScriptableObject.CreateInstance(), ScriptableObject.CreateInstance(), ScriptableObject.CreateInstance() }; } protected override void Run() { if (!(IsAvailable)) { DebugLog.OmiLAXR.Error("Face detection is not available. Disabling ."); enabled = false; StopSchedules(); return; } var fd = FaceData = FetchFaceData(); if (fd == null) return; if (!detectOnChange || _lastFaceData != null && !_lastFaceData.Equals(fd)) { OnDataUpdated?.Invoke(this, fd); } var t = Time.realtimeSinceStartupAsDouble; foreach (var e in emotions) { var was = e.IsActive; e.Evaluate(fd, t); if (was != e.IsActive) { OnEmotionChanged?.Invoke(this, new EmotionChangedEvent { Emotion = e, IsActive = e.IsActive, Intensity = e.CurrentIntensity, FaceData = FaceData }); } } _lastFaceData = FaceData; } } }