ObjectTrackingProfileEditor.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using Unity.Collections;
  9. namespace Ximmerse.XR
  10. {
  11. /// <summary>
  12. /// Tracked object json (editor only)
  13. /// </summary>
  14. [System.Serializable]
  15. internal class TrackedObjectJsonEditor
  16. {
  17. /// <summary>
  18. /// Card group json (editor only)
  19. /// </summary>
  20. [System.Serializable]
  21. public class CardGroupJsonEditor
  22. {
  23. /// <summary>
  24. /// The calibration file name.
  25. /// </summary>
  26. public string CalibFile;
  27. /// <summary>
  28. /// The type of the mode.
  29. /// </summary>
  30. public string ModeType;
  31. /// <summary>
  32. /// The group identifier.
  33. /// </summary>
  34. public int GroupID;
  35. /// <summary>
  36. /// The sub-markers.
  37. /// </summary>
  38. public int[] Markers;
  39. /// <summary>
  40. /// The size of the sub-markers.
  41. /// </summary>
  42. public float[] MarkersSize;
  43. }
  44. /// <summary>
  45. /// Single card json (editor only)
  46. /// </summary>
  47. [System.Serializable]
  48. public class SingleCardJsonEditor
  49. {
  50. /// <summary>
  51. /// The calibration file name.
  52. /// </summary>
  53. public string CalibFile;
  54. /// <summary>
  55. /// The single markers
  56. /// </summary>
  57. public int[] Markers;
  58. /// <summary>
  59. /// The size of the single markers.
  60. /// </summary>
  61. public float[] MarkersSize;
  62. public string CardIDs = string.Empty;
  63. }
  64. /// <summary>
  65. /// The card group.
  66. /// </summary>
  67. [SerializeField]
  68. public CardGroupJsonEditor CARD_GROUP = null;
  69. /// <summary>
  70. /// The card single.
  71. /// </summary>
  72. [SerializeField]
  73. public SingleCardJsonEditor CARD_SINGLE = null;
  74. public bool IsCardGroup
  75. {
  76. get
  77. {
  78. return CARD_GROUP != null && !string.IsNullOrEmpty(CARD_GROUP.CalibFile) && CARD_GROUP.GroupID >= 0;
  79. }
  80. }
  81. [System.NonSerialized]
  82. public TrackedObjectJsonEditor conflictTo = null;
  83. [System.NonSerialized]
  84. public string conflictToJson = null;
  85. public bool ValidateVs(TrackedObjectJsonEditor otherJson)
  86. {
  87. List<int> markers01 = new List<int>();
  88. if (this.IsCardGroup)
  89. {
  90. markers01.AddRange(this.CARD_GROUP.Markers);
  91. }
  92. else
  93. {
  94. markers01.AddRange(this.CARD_SINGLE.Markers);
  95. }
  96. List<int> markers02 = new List<int>();
  97. if (otherJson.IsCardGroup)
  98. {
  99. markers02.AddRange(otherJson.CARD_GROUP.Markers);
  100. }
  101. else
  102. {
  103. markers02.AddRange(otherJson.CARD_SINGLE.Markers);
  104. }
  105. if (markers01.Intersect(markers02).Count() > 0)
  106. {
  107. return false;
  108. }
  109. else return true;
  110. }
  111. }
  112. [CustomEditor(typeof(ObjectTrackingProfile))]
  113. [CanEditMultipleObjects]
  114. internal sealed class ObjectTrackingProfileInspector : UnityEditor.Editor
  115. {
  116. string errorMsg = string.Empty;
  117. string markerMsg = string.Empty;
  118. ObjectTrackingProfile mTarget
  119. {
  120. get
  121. {
  122. return this.target as ObjectTrackingProfile;
  123. }
  124. }
  125. TrackedObjectJsonEditor[] jsons = null;
  126. SerializedProperty TrackingItemArray = null;
  127. void OnEnable()
  128. {
  129. RefreshJsonItems();
  130. TrackingItemArray = serializedObject.FindProperty("items");
  131. }
  132. private void RefreshJsonItems()
  133. {
  134. jsons = mTarget.trackingItems.Select(x => JsonUtility.FromJson<TrackedObjectJsonEditor>(
  135. File.ReadAllText(AssetDatabase.GetAssetPath(x.JSONConfig))
  136. )).ToArray();
  137. foreach (var json in jsons)
  138. {
  139. //fill marker info:
  140. if (json.CARD_SINGLE != null && !string.IsNullOrEmpty(json.CARD_SINGLE.CalibFile) && json.CARD_SINGLE.Markers != null
  141. && json.CARD_SINGLE.Markers.Length > 0)
  142. {
  143. StringBuilder buffer = new StringBuilder();
  144. int c = 0;
  145. foreach (var id in json.CARD_SINGLE.Markers)
  146. {
  147. c++;
  148. if (c >= 15)
  149. {
  150. c = 0;
  151. buffer.AppendFormat("{0} \r\n", id);
  152. }
  153. else
  154. {
  155. buffer.AppendFormat("{0} ", id);
  156. }
  157. }
  158. json.CARD_SINGLE.CardIDs = buffer.ToString();
  159. }
  160. //check duplication:
  161. for (int i = 0, jsonsLength = jsons.Length; i < jsonsLength; i++)
  162. {
  163. var json2 = jsons[i];
  164. if (json != json2)
  165. {
  166. if (!json.ValidateVs(json2))
  167. {
  168. json.conflictTo = json2;
  169. json.conflictToJson = this.mTarget.trackingItems[i].JSONConfig.name;
  170. continue;
  171. }
  172. json.conflictTo = null;
  173. }
  174. }
  175. }
  176. //check config:
  177. }
  178. public override void OnInspectorGUI()
  179. {
  180. EditorGUI.BeginDisabledGroup(true);
  181. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_Script"), true);
  182. EditorGUI.EndDisabledGroup();
  183. EditorGUILayout.BeginVertical(GUI.skin.box);
  184. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Description"), true);
  185. EditorGUILayout.EndVertical();
  186. EditorGUILayout.Space();
  187. EditorGUILayout.BeginVertical(GUI.skin.box);
  188. EditorGUILayout.LabelField("--- Tracking Config ---");
  189. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_TrackBeacons"), true);
  190. //EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_TrackController"),new GUIContent("Track Right Controller"), true);
  191. //EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_TrackLeftController"), true);
  192. EditorGUILayout.EndVertical();
  193. EditorGUILayout.Space();
  194. EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_CustomTrackingCalibrationFiles"), new GUIContent("Additive Tracking"));
  195. if (mTarget.CustomTrackingCalibrationFiles)
  196. {
  197. EditorGUI.indentLevel++;
  198. DropAreaGUI();
  199. if (jsons != null && jsons.Length > 0)
  200. {
  201. EditorGUILayout.BeginVertical(GUI.skin.box);
  202. EditorGUILayout.Space();
  203. for (int i = 0, maxjsonsLength = this.jsons.Length; i < maxjsonsLength; i++)
  204. {
  205. var jItem = this.jsons[i];
  206. EditorGUILayout.BeginHorizontal();
  207. if (GUILayout.Button("X", GUILayout.MaxWidth(20)))
  208. {
  209. TrackingItemArray.DeleteArrayElementAtIndex(i);
  210. serializedObject.ApplyModifiedProperties();
  211. RefreshJsonItems();
  212. EditorGUILayout.EndHorizontal();
  213. EditorGUILayout.EndVertical();
  214. return;
  215. }
  216. EditorGUI.BeginDisabledGroup(true);
  217. EditorGUILayout.ObjectField(mTarget.trackingItems[i].JSONConfig, typeof(UnityEngine.Object), true, GUILayout.MaxWidth(200));
  218. EditorGUI.EndDisabledGroup();
  219. EditorGUILayout.EndHorizontal();
  220. if (jItem.CARD_GROUP != null && !string.IsNullOrEmpty(jItem.CARD_GROUP.CalibFile) && jItem.CARD_GROUP.GroupID >= 0)
  221. {
  222. //it's card group
  223. EditorGUILayout.LabelField(string.Format("Tracking ID: {0}", jItem.CARD_GROUP.GroupID));
  224. }
  225. else if (jItem.CARD_SINGLE != null && !string.IsNullOrEmpty(jItem.CARD_SINGLE.CardIDs))
  226. {
  227. //it's card single
  228. EditorGUILayout.TextArea(string.Format("Tracking ID: {0}", jItem.CARD_SINGLE.CardIDs), GUILayout.Height(60));
  229. }
  230. if (jItem.conflictTo != null)
  231. {
  232. EditorGUILayout.LabelField(string.Format("conflict to: {0}", jItem.conflictToJson));
  233. }
  234. EditorGUILayout.Space();
  235. }
  236. EditorGUILayout.EndVertical();
  237. }
  238. EditorGUI.indentLevel--;
  239. }
  240. serializedObject.ApplyModifiedProperties();
  241. }
  242. void DropAreaGUI()
  243. {
  244. Event evt = Event.current;
  245. Rect drop_area = GUILayoutUtility.GetRect(0.0f, 40.0f, GUILayout.ExpandWidth(true));
  246. EditorGUILayout.LabelField("[Drag JSON tracking profile to this area]");
  247. GUI.Box(drop_area, "");
  248. switch (evt.type)
  249. {
  250. case EventType.DragUpdated:
  251. case EventType.DragPerform:
  252. if (!drop_area.Contains(evt.mousePosition))
  253. return;
  254. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  255. if (evt.type == EventType.DragPerform)
  256. {
  257. DragAndDrop.AcceptDrag();
  258. var dragObjs = DragAndDrop.objectReferences;
  259. foreach (var obj in dragObjs)
  260. {
  261. if (IsValidTrackingJson(obj, out TrackedObjectJsonEditor trackedObjectData, out byte[] data))
  262. {
  263. int index = TrackingItemArray.arraySize;
  264. TrackingItemArray.InsertArrayElementAtIndex(index);
  265. serializedObject.ApplyModifiedProperties();
  266. var TrackingItemProperty = TrackingItemArray.GetArrayElementAtIndex(index);
  267. TrackingItemProperty.FindPropertyRelative("jsonName").stringValue = obj.name + ".json";
  268. TrackingItemProperty.FindPropertyRelative("JSONConfig").objectReferenceValue = obj;
  269. TrackingItemProperty.FindPropertyRelative("jsonContent").stringValue = File.ReadAllText(AssetDatabase.GetAssetPath(obj));
  270. var markerIDsProp = TrackingItemProperty.FindPropertyRelative("m_MarkerIDs");
  271. var markerSizesProp = TrackingItemProperty.FindPropertyRelative("m_MarkerSizes");
  272. var dataProp = TrackingItemProperty.FindPropertyRelative("m_Data");
  273. //Single cards:
  274. if (!trackedObjectData.IsCardGroup)
  275. {
  276. markerIDsProp.arraySize = trackedObjectData.CARD_SINGLE.Markers.Length;
  277. markerSizesProp.arraySize = trackedObjectData.CARD_SINGLE.Markers.Length;
  278. TrackingItemProperty.FindPropertyRelative("m_TrackedAsGroup").boolValue = false;
  279. for (int i = 0; i < trackedObjectData.CARD_SINGLE.Markers.Length; i++)
  280. {
  281. markerIDsProp.GetArrayElementAtIndex(i).intValue = trackedObjectData.CARD_SINGLE.Markers[i];
  282. markerSizesProp.GetArrayElementAtIndex(i).floatValue = trackedObjectData.CARD_SINGLE.MarkersSize[i];
  283. }
  284. }
  285. //Group :
  286. else
  287. {
  288. markerIDsProp.arraySize = 1;
  289. markerSizesProp.arraySize = 1;
  290. TrackingItemProperty.FindPropertyRelative("m_TrackedAsGroup").boolValue = true;
  291. markerIDsProp.GetArrayElementAtIndex(0).intValue = trackedObjectData.CARD_GROUP.GroupID;
  292. markerSizesProp.GetArrayElementAtIndex(0).floatValue = trackedObjectData.CARD_GROUP.MarkersSize[0];
  293. }
  294. //Copy data:
  295. dataProp.arraySize = data.Length;
  296. for (int i = 0; i < data.Length; i++)
  297. {
  298. dataProp.GetArrayElementAtIndex(i).intValue = data[i];
  299. }
  300. serializedObject.ApplyModifiedProperties();
  301. RefreshJsonItems();
  302. }
  303. }
  304. }
  305. break;
  306. }
  307. }
  308. bool IsValidTrackingJson(UnityEngine.Object candidate, out TrackedObjectJsonEditor trackedObjectData, out byte[] data)
  309. {
  310. trackedObjectData = null;
  311. data = null;
  312. foreach (var item in this.mTarget.trackingItems)
  313. {
  314. if (item != null && item.JSONConfig == candidate)
  315. {
  316. Debug.LogFormat("[RhinoX] Json tracking profile : {0} has already been added !", candidate.name);
  317. return false;
  318. }
  319. }
  320. bool isJson = false;
  321. try
  322. {
  323. string jsonAssetPath = AssetDatabase.GetAssetPath(candidate);
  324. string txt = File.ReadAllText(AssetDatabase.GetAssetPath(candidate));
  325. TrackedObjectJsonEditor tJson = JsonUtility.FromJson<TrackedObjectJsonEditor>(txt);
  326. trackedObjectData = tJson;
  327. //Get data:
  328. string dataAssetPath = Path.Combine(Path.GetDirectoryName(jsonAssetPath), Path.GetFileNameWithoutExtension(jsonAssetPath) + ".dat");
  329. if (File.Exists(dataAssetPath))
  330. {
  331. var bytes = File.ReadAllBytes(dataAssetPath);
  332. data = bytes;
  333. }
  334. isJson = true;
  335. }
  336. catch
  337. {
  338. isJson = false;
  339. }
  340. return isJson;
  341. }
  342. }
  343. }