Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

375 lines
14 KiB

using UnityEngine;
using Oculus.Avatar;
using System;
using System.Collections.Generic;
public delegate void specificationCallback(IntPtr specification);
public delegate void assetLoadedCallback(OvrAvatarAsset asset);
public delegate void combinedMeshLoadedCallback(IntPtr asset);
public class OvrAvatarSDKManager : MonoBehaviour
{
private static OvrAvatarSDKManager _instance;
private bool initialized = false;
private Dictionary<ulong, HashSet<specificationCallback>> specificationCallbacks;
private Dictionary<ulong, HashSet<assetLoadedCallback>> assetLoadedCallbacks;
private Dictionary<IntPtr, combinedMeshLoadedCallback> combinedMeshLoadedCallbacks;
private Dictionary<UInt64, OvrAvatarAsset> assetCache;
private OvrAvatarTextureCopyManager textureCopyManager;
public ovrAvatarLogLevel LoggingLevel = ovrAvatarLogLevel.Info;
private Queue<AvatarSpecRequestParams> avatarSpecificationQueue;
private List<int> loadingAvatars;
private bool avatarSpecRequestAvailable = true;
private float lastDispatchedAvatarSpecRequestTime = 0f;
private const float AVATAR_SPEC_REQUEST_TIMEOUT = 5f;
#if AVATAR_DEBUG
private ovrAvatarDebugContext debugContext = ovrAvatarDebugContext.None;
#endif
public struct AvatarSpecRequestParams
{
public UInt64 _userId;
public specificationCallback _callback;
public bool _useCombinedMesh;
public ovrAvatarAssetLevelOfDetail _lod;
public bool _forceMobileTextureFormat;
public ovrAvatarLookAndFeelVersion _lookVersion;
public ovrAvatarLookAndFeelVersion _fallbackVersion;
public bool _enableExpressive;
public AvatarSpecRequestParams(
UInt64 userId,
specificationCallback callback,
bool useCombinedMesh,
ovrAvatarAssetLevelOfDetail lod,
bool forceMobileTextureFormat,
ovrAvatarLookAndFeelVersion lookVersion,
ovrAvatarLookAndFeelVersion fallbackVersion,
bool enableExpressive)
{
_userId = userId;
_callback = callback;
_useCombinedMesh = useCombinedMesh;
_lod = lod;
_forceMobileTextureFormat = forceMobileTextureFormat;
_lookVersion = lookVersion;
_fallbackVersion = fallbackVersion;
_enableExpressive = enableExpressive;
}
}
public static OvrAvatarSDKManager Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.FindObjectOfType<OvrAvatarSDKManager>();
if (_instance == null)
{
GameObject manager = new GameObject("OvrAvatarSDKManager");
_instance = manager.AddComponent<OvrAvatarSDKManager>();
_instance.textureCopyManager = manager.AddComponent<OvrAvatarTextureCopyManager>();
_instance.initialized = _instance.Initialize();
}
}
return _instance.initialized ? _instance : null;
}
}
private bool Initialize()
{
CAPI.Initialize();
string appId = GetAppId();
if (appId == "")
{
AvatarLogger.LogError("No Oculus App ID has been provided for target platform. " +
"Go to Oculus Avatar > Edit Configuration to supply one", OvrAvatarSettings.Instance);
appId = "0";
}
#if UNITY_ANDROID && !UNITY_EDITOR
#if AVATAR_XPLAT
CAPI.ovrAvatar_Initialize(appId);
#else
CAPI.ovrAvatar_InitializeAndroidUnity(appId);
#endif
#else
CAPI.ovrAvatar_Initialize(appId);
CAPI.SendEvent("initialize", appId);
#endif
specificationCallbacks = new Dictionary<UInt64, HashSet<specificationCallback>>();
assetLoadedCallbacks = new Dictionary<UInt64, HashSet<assetLoadedCallback>>();
combinedMeshLoadedCallbacks = new Dictionary<IntPtr, combinedMeshLoadedCallback>();
assetCache = new Dictionary<ulong, OvrAvatarAsset>();
avatarSpecificationQueue = new Queue<AvatarSpecRequestParams>();
loadingAvatars = new List<int>();
CAPI.ovrAvatar_SetLoggingLevel(LoggingLevel);
CAPI.ovrAvatar_RegisterLoggingCallback(CAPI.LoggingCallback);
#if AVATAR_DEBUG
CAPI.ovrAvatar_SetDebugDrawContext((uint)debugContext);
#endif
return true;
}
void OnDestroy()
{
CAPI.Shutdown();
CAPI.ovrAvatar_RegisterLoggingCallback(null);
CAPI.ovrAvatar_Shutdown();
}
void Update()
{
if (Instance == null)
{
return;
}
#if AVATAR_DEBUG
// Call before ovrAvatarMessage_Pop which flushes the state
CAPI.ovrAvatar_DrawDebugLines();
#endif
// Dispatch waiting avatar spec request
if (avatarSpecificationQueue.Count > 0 &&
(avatarSpecRequestAvailable ||
Time.time - lastDispatchedAvatarSpecRequestTime >= AVATAR_SPEC_REQUEST_TIMEOUT))
{
avatarSpecRequestAvailable = false;
AvatarSpecRequestParams avatarSpec = avatarSpecificationQueue.Dequeue();
DispatchAvatarSpecificationRequest(avatarSpec);
lastDispatchedAvatarSpecRequestTime = Time.time;
AvatarLogger.Log("Avatar spec request dispatched: " + avatarSpec._userId);
}
IntPtr message = CAPI.ovrAvatarMessage_Pop();
if (message == IntPtr.Zero)
{
return;
}
ovrAvatarMessageType messageType = CAPI.ovrAvatarMessage_GetType(message);
switch (messageType)
{
case ovrAvatarMessageType.AssetLoaded:
{
ovrAvatarMessage_AssetLoaded assetMessage = CAPI.ovrAvatarMessage_GetAssetLoaded(message);
IntPtr asset = assetMessage.asset;
UInt64 assetID = assetMessage.assetID;
ovrAvatarAssetType assetType = CAPI.ovrAvatarAsset_GetType(asset);
OvrAvatarAsset assetData = null;
IntPtr avatarOwner = IntPtr.Zero;
switch (assetType)
{
case ovrAvatarAssetType.Mesh:
assetData = new OvrAvatarAssetMesh(assetID, asset, ovrAvatarAssetType.Mesh);
break;
case ovrAvatarAssetType.Texture:
assetData = new OvrAvatarAssetTexture(assetID, asset);
break;
case ovrAvatarAssetType.Material:
assetData = new OvrAvatarAssetMaterial(assetID, asset);
break;
case ovrAvatarAssetType.CombinedMesh:
avatarOwner = CAPI.ovrAvatarAsset_GetAvatar(asset);
assetData = new OvrAvatarAssetMesh(assetID, asset, ovrAvatarAssetType.CombinedMesh);
break;
case ovrAvatarAssetType.FailedLoad:
AvatarLogger.LogWarning("Asset failed to load from SDK " + assetID);
break;
default:
throw new NotImplementedException(string.Format("Unsupported asset type format {0}", assetType.ToString()));
}
HashSet<assetLoadedCallback> callbackSet;
if (assetType == ovrAvatarAssetType.CombinedMesh)
{
if (!assetCache.ContainsKey(assetID))
{
assetCache.Add(assetID, assetData);
}
combinedMeshLoadedCallback callback;
if (combinedMeshLoadedCallbacks.TryGetValue(avatarOwner, out callback))
{
callback(asset);
combinedMeshLoadedCallbacks.Remove(avatarOwner);
}
else
{
AvatarLogger.LogWarning("Loaded a combined mesh with no owner: " + assetMessage.assetID);
}
}
else
{
if (assetData != null && assetLoadedCallbacks.TryGetValue(assetMessage.assetID, out callbackSet))
{
assetCache.Add(assetID, assetData);
foreach (var callback in callbackSet)
{
callback(assetData);
}
assetLoadedCallbacks.Remove(assetMessage.assetID);
}
}
break;
}
case ovrAvatarMessageType.AvatarSpecification:
{
avatarSpecRequestAvailable = true;
ovrAvatarMessage_AvatarSpecification spec = CAPI.ovrAvatarMessage_GetAvatarSpecification(message);
HashSet<specificationCallback> callbackSet;
if (specificationCallbacks.TryGetValue(spec.oculusUserID, out callbackSet))
{
foreach (var callback in callbackSet)
{
callback(spec.avatarSpec);
}
specificationCallbacks.Remove(spec.oculusUserID);
}
else
{
AvatarLogger.LogWarning("Error, got an avatar specification callback from a user id we don't have a record for: " + spec.oculusUserID);
}
break;
}
default:
throw new NotImplementedException("Unhandled ovrAvatarMessageType: " + messageType);
}
CAPI.ovrAvatarMessage_Free(message);
}
public bool IsAvatarSpecWaiting()
{
return avatarSpecificationQueue.Count > 0;
}
public bool IsAvatarLoading()
{
return loadingAvatars.Count > 0;
}
// Add avatar gameobject ID to loading list to keep track of loading avatars
public void AddLoadingAvatar(int gameobjectID)
{
loadingAvatars.Add(gameobjectID);
}
// Remove avatar gameobject ID from loading list
public void RemoveLoadingAvatar(int gameobjectID)
{
loadingAvatars.Remove(gameobjectID);
}
// Request an avatar specification to be loaded by adding to the queue.
// Requests are dispatched in Update().
public void RequestAvatarSpecification(AvatarSpecRequestParams avatarSpecRequest)
{
avatarSpecificationQueue.Enqueue(avatarSpecRequest);
AvatarLogger.Log("Avatar spec request queued: " + avatarSpecRequest._userId.ToString());
}
private void DispatchAvatarSpecificationRequest(AvatarSpecRequestParams avatarSpecRequest)
{
textureCopyManager.CheckFallbackTextureSet(avatarSpecRequest._lod);
CAPI.ovrAvatar_SetForceASTCTextures(avatarSpecRequest._forceMobileTextureFormat);
HashSet<specificationCallback> callbackSet;
if (!specificationCallbacks.TryGetValue(avatarSpecRequest._userId, out callbackSet))
{
callbackSet = new HashSet<specificationCallback>();
specificationCallbacks.Add(avatarSpecRequest._userId, callbackSet);
IntPtr specRequest = CAPI.ovrAvatarSpecificationRequest_Create(avatarSpecRequest._userId);
CAPI.ovrAvatarSpecificationRequest_SetLookAndFeelVersion(specRequest, avatarSpecRequest._lookVersion);
CAPI.ovrAvatarSpecificationRequest_SetFallbackLookAndFeelVersion(specRequest, avatarSpecRequest._fallbackVersion);
CAPI.ovrAvatarSpecificationRequest_SetLevelOfDetail(specRequest, avatarSpecRequest._lod);
CAPI.ovrAvatarSpecificationRequest_SetCombineMeshes(specRequest, avatarSpecRequest._useCombinedMesh);
CAPI.ovrAvatarSpecificationRequest_SetExpressiveFlag(specRequest, avatarSpecRequest._enableExpressive);
CAPI.ovrAvatar_RequestAvatarSpecificationFromSpecRequest(specRequest);
CAPI.ovrAvatarSpecificationRequest_Destroy(specRequest);
}
callbackSet.Add(avatarSpecRequest._callback);
}
public void BeginLoadingAsset(
UInt64 assetId,
ovrAvatarAssetLevelOfDetail lod,
assetLoadedCallback callback)
{
HashSet<assetLoadedCallback> callbackSet;
if (!assetLoadedCallbacks.TryGetValue(assetId, out callbackSet))
{
callbackSet = new HashSet<assetLoadedCallback>();
assetLoadedCallbacks.Add(assetId, callbackSet);
}
AvatarLogger.Log("Loading Asset ID: " + assetId);
CAPI.ovrAvatarAsset_BeginLoadingLOD(assetId, lod);
callbackSet.Add(callback);
}
public void RegisterCombinedMeshCallback(
IntPtr sdkAvatar,
combinedMeshLoadedCallback callback)
{
combinedMeshLoadedCallback currentCallback;
if (!combinedMeshLoadedCallbacks.TryGetValue(sdkAvatar, out currentCallback))
{
combinedMeshLoadedCallbacks.Add(sdkAvatar, callback);
}
else
{
throw new Exception("Adding second combind mesh callback for same avatar");
}
}
public OvrAvatarAsset GetAsset(UInt64 assetId)
{
OvrAvatarAsset asset;
if (assetCache.TryGetValue(assetId, out asset))
{
return asset;
}
else
{
return null;
}
}
public void DeleteAssetFromCache(UInt64 assetId)
{
if (assetCache.ContainsKey(assetId))
{
assetCache.Remove(assetId);
}
}
public string GetAppId()
{
return UnityEngine.Application.platform == RuntimePlatform.Android ?
OvrAvatarSettings.MobileAppID : OvrAvatarSettings.AppID;
}
public OvrAvatarTextureCopyManager GetTextureCopyManager()
{
if (textureCopyManager != null)
{
return textureCopyManager;
}
else
{
return null;
}
}
}