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

  1. using UnityEngine;
  2. using Oculus.Avatar;
  3. using System;
  4. using System.Collections.Generic;
  5. public delegate void specificationCallback(IntPtr specification);
  6. public delegate void assetLoadedCallback(OvrAvatarAsset asset);
  7. public delegate void combinedMeshLoadedCallback(IntPtr asset);
  8. public class OvrAvatarSDKManager : MonoBehaviour
  9. {
  10. private static OvrAvatarSDKManager _instance;
  11. private bool initialized = false;
  12. private Dictionary<ulong, HashSet<specificationCallback>> specificationCallbacks;
  13. private Dictionary<ulong, HashSet<assetLoadedCallback>> assetLoadedCallbacks;
  14. private Dictionary<IntPtr, combinedMeshLoadedCallback> combinedMeshLoadedCallbacks;
  15. private Dictionary<UInt64, OvrAvatarAsset> assetCache;
  16. private OvrAvatarTextureCopyManager textureCopyManager;
  17. public ovrAvatarLogLevel LoggingLevel = ovrAvatarLogLevel.Info;
  18. private Queue<AvatarSpecRequestParams> avatarSpecificationQueue;
  19. private List<int> loadingAvatars;
  20. private bool avatarSpecRequestAvailable = true;
  21. private float lastDispatchedAvatarSpecRequestTime = 0f;
  22. private const float AVATAR_SPEC_REQUEST_TIMEOUT = 5f;
  23. #if AVATAR_DEBUG
  24. private ovrAvatarDebugContext debugContext = ovrAvatarDebugContext.None;
  25. #endif
  26. public struct AvatarSpecRequestParams
  27. {
  28. public UInt64 _userId;
  29. public specificationCallback _callback;
  30. public bool _useCombinedMesh;
  31. public ovrAvatarAssetLevelOfDetail _lod;
  32. public bool _forceMobileTextureFormat;
  33. public ovrAvatarLookAndFeelVersion _lookVersion;
  34. public ovrAvatarLookAndFeelVersion _fallbackVersion;
  35. public bool _enableExpressive;
  36. public AvatarSpecRequestParams(
  37. UInt64 userId,
  38. specificationCallback callback,
  39. bool useCombinedMesh,
  40. ovrAvatarAssetLevelOfDetail lod,
  41. bool forceMobileTextureFormat,
  42. ovrAvatarLookAndFeelVersion lookVersion,
  43. ovrAvatarLookAndFeelVersion fallbackVersion,
  44. bool enableExpressive)
  45. {
  46. _userId = userId;
  47. _callback = callback;
  48. _useCombinedMesh = useCombinedMesh;
  49. _lod = lod;
  50. _forceMobileTextureFormat = forceMobileTextureFormat;
  51. _lookVersion = lookVersion;
  52. _fallbackVersion = fallbackVersion;
  53. _enableExpressive = enableExpressive;
  54. }
  55. }
  56. public static OvrAvatarSDKManager Instance
  57. {
  58. get
  59. {
  60. if (_instance == null)
  61. {
  62. _instance = GameObject.FindObjectOfType<OvrAvatarSDKManager>();
  63. if (_instance == null)
  64. {
  65. GameObject manager = new GameObject("OvrAvatarSDKManager");
  66. _instance = manager.AddComponent<OvrAvatarSDKManager>();
  67. _instance.textureCopyManager = manager.AddComponent<OvrAvatarTextureCopyManager>();
  68. _instance.initialized = _instance.Initialize();
  69. }
  70. }
  71. return _instance.initialized ? _instance : null;
  72. }
  73. }
  74. private bool Initialize()
  75. {
  76. CAPI.Initialize();
  77. string appId = GetAppId();
  78. if (appId == "")
  79. {
  80. AvatarLogger.LogError("No Oculus App ID has been provided for target platform. " +
  81. "Go to Oculus Avatar > Edit Configuration to supply one", OvrAvatarSettings.Instance);
  82. appId = "0";
  83. }
  84. #if UNITY_ANDROID && !UNITY_EDITOR
  85. #if AVATAR_XPLAT
  86. CAPI.ovrAvatar_Initialize(appId);
  87. #else
  88. CAPI.ovrAvatar_InitializeAndroidUnity(appId);
  89. #endif
  90. #else
  91. CAPI.ovrAvatar_Initialize(appId);
  92. CAPI.SendEvent("initialize", appId);
  93. #endif
  94. specificationCallbacks = new Dictionary<UInt64, HashSet<specificationCallback>>();
  95. assetLoadedCallbacks = new Dictionary<UInt64, HashSet<assetLoadedCallback>>();
  96. combinedMeshLoadedCallbacks = new Dictionary<IntPtr, combinedMeshLoadedCallback>();
  97. assetCache = new Dictionary<ulong, OvrAvatarAsset>();
  98. avatarSpecificationQueue = new Queue<AvatarSpecRequestParams>();
  99. loadingAvatars = new List<int>();
  100. CAPI.ovrAvatar_SetLoggingLevel(LoggingLevel);
  101. CAPI.ovrAvatar_RegisterLoggingCallback(CAPI.LoggingCallback);
  102. #if AVATAR_DEBUG
  103. CAPI.ovrAvatar_SetDebugDrawContext((uint)debugContext);
  104. #endif
  105. return true;
  106. }
  107. void OnDestroy()
  108. {
  109. CAPI.Shutdown();
  110. CAPI.ovrAvatar_RegisterLoggingCallback(null);
  111. CAPI.ovrAvatar_Shutdown();
  112. }
  113. void Update()
  114. {
  115. if (Instance == null)
  116. {
  117. return;
  118. }
  119. #if AVATAR_DEBUG
  120. // Call before ovrAvatarMessage_Pop which flushes the state
  121. CAPI.ovrAvatar_DrawDebugLines();
  122. #endif
  123. // Dispatch waiting avatar spec request
  124. if (avatarSpecificationQueue.Count > 0 &&
  125. (avatarSpecRequestAvailable ||
  126. Time.time - lastDispatchedAvatarSpecRequestTime >= AVATAR_SPEC_REQUEST_TIMEOUT))
  127. {
  128. avatarSpecRequestAvailable = false;
  129. AvatarSpecRequestParams avatarSpec = avatarSpecificationQueue.Dequeue();
  130. DispatchAvatarSpecificationRequest(avatarSpec);
  131. lastDispatchedAvatarSpecRequestTime = Time.time;
  132. AvatarLogger.Log("Avatar spec request dispatched: " + avatarSpec._userId);
  133. }
  134. IntPtr message = CAPI.ovrAvatarMessage_Pop();
  135. if (message == IntPtr.Zero)
  136. {
  137. return;
  138. }
  139. ovrAvatarMessageType messageType = CAPI.ovrAvatarMessage_GetType(message);
  140. switch (messageType)
  141. {
  142. case ovrAvatarMessageType.AssetLoaded:
  143. {
  144. ovrAvatarMessage_AssetLoaded assetMessage = CAPI.ovrAvatarMessage_GetAssetLoaded(message);
  145. IntPtr asset = assetMessage.asset;
  146. UInt64 assetID = assetMessage.assetID;
  147. ovrAvatarAssetType assetType = CAPI.ovrAvatarAsset_GetType(asset);
  148. OvrAvatarAsset assetData = null;
  149. IntPtr avatarOwner = IntPtr.Zero;
  150. switch (assetType)
  151. {
  152. case ovrAvatarAssetType.Mesh:
  153. assetData = new OvrAvatarAssetMesh(assetID, asset, ovrAvatarAssetType.Mesh);
  154. break;
  155. case ovrAvatarAssetType.Texture:
  156. assetData = new OvrAvatarAssetTexture(assetID, asset);
  157. break;
  158. case ovrAvatarAssetType.Material:
  159. assetData = new OvrAvatarAssetMaterial(assetID, asset);
  160. break;
  161. case ovrAvatarAssetType.CombinedMesh:
  162. avatarOwner = CAPI.ovrAvatarAsset_GetAvatar(asset);
  163. assetData = new OvrAvatarAssetMesh(assetID, asset, ovrAvatarAssetType.CombinedMesh);
  164. break;
  165. case ovrAvatarAssetType.FailedLoad:
  166. AvatarLogger.LogWarning("Asset failed to load from SDK " + assetID);
  167. break;
  168. default:
  169. throw new NotImplementedException(string.Format("Unsupported asset type format {0}", assetType.ToString()));
  170. }
  171. HashSet<assetLoadedCallback> callbackSet;
  172. if (assetType == ovrAvatarAssetType.CombinedMesh)
  173. {
  174. if (!assetCache.ContainsKey(assetID))
  175. {
  176. assetCache.Add(assetID, assetData);
  177. }
  178. combinedMeshLoadedCallback callback;
  179. if (combinedMeshLoadedCallbacks.TryGetValue(avatarOwner, out callback))
  180. {
  181. callback(asset);
  182. combinedMeshLoadedCallbacks.Remove(avatarOwner);
  183. }
  184. else
  185. {
  186. AvatarLogger.LogWarning("Loaded a combined mesh with no owner: " + assetMessage.assetID);
  187. }
  188. }
  189. else
  190. {
  191. if (assetData != null && assetLoadedCallbacks.TryGetValue(assetMessage.assetID, out callbackSet))
  192. {
  193. assetCache.Add(assetID, assetData);
  194. foreach (var callback in callbackSet)
  195. {
  196. callback(assetData);
  197. }
  198. assetLoadedCallbacks.Remove(assetMessage.assetID);
  199. }
  200. }
  201. break;
  202. }
  203. case ovrAvatarMessageType.AvatarSpecification:
  204. {
  205. avatarSpecRequestAvailable = true;
  206. ovrAvatarMessage_AvatarSpecification spec = CAPI.ovrAvatarMessage_GetAvatarSpecification(message);
  207. HashSet<specificationCallback> callbackSet;
  208. if (specificationCallbacks.TryGetValue(spec.oculusUserID, out callbackSet))
  209. {
  210. foreach (var callback in callbackSet)
  211. {
  212. callback(spec.avatarSpec);
  213. }
  214. specificationCallbacks.Remove(spec.oculusUserID);
  215. }
  216. else
  217. {
  218. AvatarLogger.LogWarning("Error, got an avatar specification callback from a user id we don't have a record for: " + spec.oculusUserID);
  219. }
  220. break;
  221. }
  222. default:
  223. throw new NotImplementedException("Unhandled ovrAvatarMessageType: " + messageType);
  224. }
  225. CAPI.ovrAvatarMessage_Free(message);
  226. }
  227. public bool IsAvatarSpecWaiting()
  228. {
  229. return avatarSpecificationQueue.Count > 0;
  230. }
  231. public bool IsAvatarLoading()
  232. {
  233. return loadingAvatars.Count > 0;
  234. }
  235. // Add avatar gameobject ID to loading list to keep track of loading avatars
  236. public void AddLoadingAvatar(int gameobjectID)
  237. {
  238. loadingAvatars.Add(gameobjectID);
  239. }
  240. // Remove avatar gameobject ID from loading list
  241. public void RemoveLoadingAvatar(int gameobjectID)
  242. {
  243. loadingAvatars.Remove(gameobjectID);
  244. }
  245. // Request an avatar specification to be loaded by adding to the queue.
  246. // Requests are dispatched in Update().
  247. public void RequestAvatarSpecification(AvatarSpecRequestParams avatarSpecRequest)
  248. {
  249. avatarSpecificationQueue.Enqueue(avatarSpecRequest);
  250. AvatarLogger.Log("Avatar spec request queued: " + avatarSpecRequest._userId.ToString());
  251. }
  252. private void DispatchAvatarSpecificationRequest(AvatarSpecRequestParams avatarSpecRequest)
  253. {
  254. textureCopyManager.CheckFallbackTextureSet(avatarSpecRequest._lod);
  255. CAPI.ovrAvatar_SetForceASTCTextures(avatarSpecRequest._forceMobileTextureFormat);
  256. HashSet<specificationCallback> callbackSet;
  257. if (!specificationCallbacks.TryGetValue(avatarSpecRequest._userId, out callbackSet))
  258. {
  259. callbackSet = new HashSet<specificationCallback>();
  260. specificationCallbacks.Add(avatarSpecRequest._userId, callbackSet);
  261. IntPtr specRequest = CAPI.ovrAvatarSpecificationRequest_Create(avatarSpecRequest._userId);
  262. CAPI.ovrAvatarSpecificationRequest_SetLookAndFeelVersion(specRequest, avatarSpecRequest._lookVersion);
  263. CAPI.ovrAvatarSpecificationRequest_SetFallbackLookAndFeelVersion(specRequest, avatarSpecRequest._fallbackVersion);
  264. CAPI.ovrAvatarSpecificationRequest_SetLevelOfDetail(specRequest, avatarSpecRequest._lod);
  265. CAPI.ovrAvatarSpecificationRequest_SetCombineMeshes(specRequest, avatarSpecRequest._useCombinedMesh);
  266. CAPI.ovrAvatarSpecificationRequest_SetExpressiveFlag(specRequest, avatarSpecRequest._enableExpressive);
  267. CAPI.ovrAvatar_RequestAvatarSpecificationFromSpecRequest(specRequest);
  268. CAPI.ovrAvatarSpecificationRequest_Destroy(specRequest);
  269. }
  270. callbackSet.Add(avatarSpecRequest._callback);
  271. }
  272. public void BeginLoadingAsset(
  273. UInt64 assetId,
  274. ovrAvatarAssetLevelOfDetail lod,
  275. assetLoadedCallback callback)
  276. {
  277. HashSet<assetLoadedCallback> callbackSet;
  278. if (!assetLoadedCallbacks.TryGetValue(assetId, out callbackSet))
  279. {
  280. callbackSet = new HashSet<assetLoadedCallback>();
  281. assetLoadedCallbacks.Add(assetId, callbackSet);
  282. }
  283. AvatarLogger.Log("Loading Asset ID: " + assetId);
  284. CAPI.ovrAvatarAsset_BeginLoadingLOD(assetId, lod);
  285. callbackSet.Add(callback);
  286. }
  287. public void RegisterCombinedMeshCallback(
  288. IntPtr sdkAvatar,
  289. combinedMeshLoadedCallback callback)
  290. {
  291. combinedMeshLoadedCallback currentCallback;
  292. if (!combinedMeshLoadedCallbacks.TryGetValue(sdkAvatar, out currentCallback))
  293. {
  294. combinedMeshLoadedCallbacks.Add(sdkAvatar, callback);
  295. }
  296. else
  297. {
  298. throw new Exception("Adding second combind mesh callback for same avatar");
  299. }
  300. }
  301. public OvrAvatarAsset GetAsset(UInt64 assetId)
  302. {
  303. OvrAvatarAsset asset;
  304. if (assetCache.TryGetValue(assetId, out asset))
  305. {
  306. return asset;
  307. }
  308. else
  309. {
  310. return null;
  311. }
  312. }
  313. public void DeleteAssetFromCache(UInt64 assetId)
  314. {
  315. if (assetCache.ContainsKey(assetId))
  316. {
  317. assetCache.Remove(assetId);
  318. }
  319. }
  320. public string GetAppId()
  321. {
  322. return UnityEngine.Application.platform == RuntimePlatform.Android ?
  323. OvrAvatarSettings.MobileAppID : OvrAvatarSettings.AppID;
  324. }
  325. public OvrAvatarTextureCopyManager GetTextureCopyManager()
  326. {
  327. if (textureCopyManager != null)
  328. {
  329. return textureCopyManager;
  330. }
  331. else
  332. {
  333. return null;
  334. }
  335. }
  336. }