using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Service;
using UnityEngine;
namespace Convai.Scripts.Utils.LipSync
{
///
/// This Class will serve as a base for any method of Lipsync that Convai will develop or use
///
public abstract class ConvaiLipSyncApplicationBase : MonoBehaviour
{
///
/// This stores a dictionary of blendshape name and index of the Blendweight it will affect
///
protected Dictionary _headMapping;
///
/// Reference to the Head Skin Mesh Renderer used for lipsync
///
protected SkinnedMeshRenderer _headSkinMeshRenderer;
///
/// Reference to the Teeth Skin Mesh Renderer used for lipsync
///
protected SkinnedMeshRenderer _teethSkinMeshRenderer;
///
/// Reference to the Jaw bone gameobject used for lipsync
///
private GameObject _jawBone;
///
/// Reference to the Tongue bone gameobject used for lipsync
///
private GameObject _tongueBone;
///
/// Reference to the NPC on which lipsync will be applied
///
protected ConvaiNPC _convaiNPC;
protected float _weightMultiplier { get; private set; }
#region Null States of References
protected bool HasHeadSkinnedMeshRenderer { get; private set; }
protected bool HasTeethSkinnedMeshRenderer { get; private set; }
protected bool HasJawBone { get; private set; }
protected bool HasTongueBone { get; private set; }
#endregion
///
/// Initializes and setup up of the things necessary for lipsync to work
///
///
///
public virtual void Initialize(ConvaiLipSync convaiLipSync, ConvaiNPC convaiNPC)
{
_headSkinMeshRenderer = convaiLipSync.HeadSkinnedMeshRenderer;
HasHeadSkinnedMeshRenderer = _headSkinMeshRenderer != null;
_teethSkinMeshRenderer = convaiLipSync.TeethSkinnedMeshRenderer;
HasTeethSkinnedMeshRenderer = _teethSkinMeshRenderer != null;
_jawBone = convaiLipSync.jawBone;
HasJawBone = _jawBone != null;
_tongueBone = convaiLipSync.tongueBone;
HasTongueBone = _tongueBone != null;
_convaiNPC = convaiNPC;
_weightMultiplier = convaiLipSync != null ? convaiLipSync.WeightMultiplier : 1;
if (HasHeadSkinnedMeshRenderer)
_headMapping = SetupMapping(GetHeadRegexMapping, _headSkinMeshRenderer);
}
///
/// Creates the mapping of blendshape and index it affects during lipsync
///
protected Dictionary SetupMapping(Func> finder, SkinnedMeshRenderer skinnedMeshRenderer)
{
Dictionary mapping = new Dictionary();
Dictionary regexMapping = finder();
foreach (KeyValuePair pair in regexMapping)
{
for (int i = 0; i < skinnedMeshRenderer.sharedMesh.blendShapeCount; i++)
{
string blendShapeName = skinnedMeshRenderer.sharedMesh.GetBlendShapeName(i);
Regex regex = new(pair.Value);
if (regex.IsMatch(blendShapeName))
{
mapping.TryAdd(pair.Key, i);
}
}
}
return mapping;
}
///
/// Returns a dictionary of blendshape name and regex string used to find the index
/// TODO Modify the override to fit your version of the mapping
///
///
protected virtual Dictionary GetHeadRegexMapping()
{
return new Dictionary();
}
///
/// Updates the tongue bone rotation to the new rotation
///
///
protected void UpdateTongueBoneRotation(Vector3 newRotation)
{
if (!HasTongueBone) return;
_tongueBone.transform.localEulerAngles = newRotation;
}
///
/// Updates the jaw bone rotation to the new rotation
///
///
protected void UpdateJawBoneRotation(Vector3 newRotation)
{
if (!HasJawBone) return;
_jawBone.transform.localEulerAngles = newRotation;
}
///
/// Updates the current blendshape or visemes frame
///
protected abstract void UpdateBlendShape();
///
/// This removes the excess frames in the queue
///
public abstract void PurgeExcessBlendShapeFrames();
///
/// This resets the whole queue of the frames
///
protected bool CanPurge(Queue queue)
{
// ? Should I hardcode the limiter for this check
return queue.Count < 10;
}
public abstract void ClearQueue();
///
/// Adds blendshape frames in the queue
///
///
public virtual void EnqueueQueue(Queue blendshapeFrames) { }
///
/// Adds Visemes frames in the list
///
///
public virtual void EnqueueQueue(Queue visemesFrames) { }
///
/// Adds a blendshape frame in the last queue
///
///
public virtual void EnqueueFrame(BlendshapeFrame blendshapeFrame) { }
///
/// Adds a viseme frame to the last element of the list
///
///
public virtual void EnqueueFrame(VisemesData viseme) { }
}
}