using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using System.Text; using Unity.Collections; namespace Ximmerse.XR { /// /// Tracked object json (editor only) /// [System.Serializable] internal class TrackedObjectJsonEditor { /// /// Card group json (editor only) /// [System.Serializable] public class CardGroupJsonEditor { /// /// The calibration file name. /// public string CalibFile; /// /// The type of the mode. /// public string ModeType; /// /// The group identifier. /// public int GroupID; /// /// The sub-markers. /// public int[] Markers; /// /// The size of the sub-markers. /// public float[] MarkersSize; } /// /// Single card json (editor only) /// [System.Serializable] public class SingleCardJsonEditor { /// /// The calibration file name. /// public string CalibFile; /// /// The single markers /// public int[] Markers; /// /// The size of the single markers. /// public float[] MarkersSize; public string CardIDs = string.Empty; } /// /// The card group. /// [SerializeField] public CardGroupJsonEditor CARD_GROUP = null; /// /// The card single. /// [SerializeField] public SingleCardJsonEditor CARD_SINGLE = null; public bool IsCardGroup { get { return CARD_GROUP != null && !string.IsNullOrEmpty(CARD_GROUP.CalibFile) && CARD_GROUP.GroupID >= 0; } } [System.NonSerialized] public TrackedObjectJsonEditor conflictTo = null; [System.NonSerialized] public string conflictToJson = null; public bool ValidateVs(TrackedObjectJsonEditor otherJson) { List markers01 = new List(); if (this.IsCardGroup) { markers01.AddRange(this.CARD_GROUP.Markers); } else { markers01.AddRange(this.CARD_SINGLE.Markers); } List markers02 = new List(); if (otherJson.IsCardGroup) { markers02.AddRange(otherJson.CARD_GROUP.Markers); } else { markers02.AddRange(otherJson.CARD_SINGLE.Markers); } if (markers01.Intersect(markers02).Count() > 0) { return false; } else return true; } } [CustomEditor(typeof(ObjectTrackingProfile))] [CanEditMultipleObjects] internal sealed class ObjectTrackingProfileInspector : UnityEditor.Editor { string errorMsg = string.Empty; string markerMsg = string.Empty; ObjectTrackingProfile mTarget { get { return this.target as ObjectTrackingProfile; } } TrackedObjectJsonEditor[] jsons = null; SerializedProperty TrackingItemArray = null; void OnEnable() { RefreshJsonItems(); TrackingItemArray = serializedObject.FindProperty("items"); } private void RefreshJsonItems() { jsons = mTarget.trackingItems.Select(x => JsonUtility.FromJson( File.ReadAllText(AssetDatabase.GetAssetPath(x.JSONConfig)) )).ToArray(); foreach (var json in jsons) { //fill marker info: if (json.CARD_SINGLE != null && !string.IsNullOrEmpty(json.CARD_SINGLE.CalibFile) && json.CARD_SINGLE.Markers != null && json.CARD_SINGLE.Markers.Length > 0) { StringBuilder buffer = new StringBuilder(); int c = 0; foreach (var id in json.CARD_SINGLE.Markers) { c++; if (c >= 15) { c = 0; buffer.AppendFormat("{0} \r\n", id); } else { buffer.AppendFormat("{0} ", id); } } json.CARD_SINGLE.CardIDs = buffer.ToString(); } //check duplication: for (int i = 0, jsonsLength = jsons.Length; i < jsonsLength; i++) { var json2 = jsons[i]; if (json != json2) { if (!json.ValidateVs(json2)) { json.conflictTo = json2; json.conflictToJson = this.mTarget.trackingItems[i].JSONConfig.name; continue; } json.conflictTo = null; } } } //check config: } public override void OnInspectorGUI() { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_Script"), true); EditorGUI.EndDisabledGroup(); EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Description"), true); EditorGUILayout.EndVertical(); EditorGUILayout.Space(); EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUILayout.LabelField("--- Tracking Config ---"); EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_TrackBeacons"), true); //EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_TrackController"),new GUIContent("Track Right Controller"), true); //EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_TrackLeftController"), true); EditorGUILayout.EndVertical(); EditorGUILayout.Space(); EditorGUILayout.PropertyField(this.serializedObject.FindProperty("m_CustomTrackingCalibrationFiles"), new GUIContent("Additive Tracking")); if (mTarget.CustomTrackingCalibrationFiles) { EditorGUI.indentLevel++; DropAreaGUI(); if (jsons != null && jsons.Length > 0) { EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUILayout.Space(); for (int i = 0, maxjsonsLength = this.jsons.Length; i < maxjsonsLength; i++) { var jItem = this.jsons[i]; EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("X", GUILayout.MaxWidth(20))) { TrackingItemArray.DeleteArrayElementAtIndex(i); serializedObject.ApplyModifiedProperties(); RefreshJsonItems(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); return; } EditorGUI.BeginDisabledGroup(true); EditorGUILayout.ObjectField(mTarget.trackingItems[i].JSONConfig, typeof(UnityEngine.Object), true, GUILayout.MaxWidth(200)); EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); if (jItem.CARD_GROUP != null && !string.IsNullOrEmpty(jItem.CARD_GROUP.CalibFile) && jItem.CARD_GROUP.GroupID >= 0) { //it's card group EditorGUILayout.LabelField(string.Format("Tracking ID: {0}", jItem.CARD_GROUP.GroupID)); } else if (jItem.CARD_SINGLE != null && !string.IsNullOrEmpty(jItem.CARD_SINGLE.CardIDs)) { //it's card single EditorGUILayout.TextArea(string.Format("Tracking ID: {0}", jItem.CARD_SINGLE.CardIDs), GUILayout.Height(60)); } if (jItem.conflictTo != null) { EditorGUILayout.LabelField(string.Format("conflict to: {0}", jItem.conflictToJson)); } EditorGUILayout.Space(); } EditorGUILayout.EndVertical(); } EditorGUI.indentLevel--; } serializedObject.ApplyModifiedProperties(); } void DropAreaGUI() { Event evt = Event.current; Rect drop_area = GUILayoutUtility.GetRect(0.0f, 40.0f, GUILayout.ExpandWidth(true)); EditorGUILayout.LabelField("[Drag JSON tracking profile to this area]"); GUI.Box(drop_area, ""); switch (evt.type) { case EventType.DragUpdated: case EventType.DragPerform: if (!drop_area.Contains(evt.mousePosition)) return; DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (evt.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); var dragObjs = DragAndDrop.objectReferences; foreach (var obj in dragObjs) { if (IsValidTrackingJson(obj, out TrackedObjectJsonEditor trackedObjectData, out byte[] data)) { int index = TrackingItemArray.arraySize; TrackingItemArray.InsertArrayElementAtIndex(index); serializedObject.ApplyModifiedProperties(); var TrackingItemProperty = TrackingItemArray.GetArrayElementAtIndex(index); TrackingItemProperty.FindPropertyRelative("jsonName").stringValue = obj.name + ".json"; TrackingItemProperty.FindPropertyRelative("JSONConfig").objectReferenceValue = obj; TrackingItemProperty.FindPropertyRelative("jsonContent").stringValue = File.ReadAllText(AssetDatabase.GetAssetPath(obj)); var markerIDsProp = TrackingItemProperty.FindPropertyRelative("m_MarkerIDs"); var markerSizesProp = TrackingItemProperty.FindPropertyRelative("m_MarkerSizes"); var dataProp = TrackingItemProperty.FindPropertyRelative("m_Data"); //Single cards: if (!trackedObjectData.IsCardGroup) { markerIDsProp.arraySize = trackedObjectData.CARD_SINGLE.Markers.Length; markerSizesProp.arraySize = trackedObjectData.CARD_SINGLE.Markers.Length; TrackingItemProperty.FindPropertyRelative("m_TrackedAsGroup").boolValue = false; for (int i = 0; i < trackedObjectData.CARD_SINGLE.Markers.Length; i++) { markerIDsProp.GetArrayElementAtIndex(i).intValue = trackedObjectData.CARD_SINGLE.Markers[i]; markerSizesProp.GetArrayElementAtIndex(i).floatValue = trackedObjectData.CARD_SINGLE.MarkersSize[i]; } } //Group : else { markerIDsProp.arraySize = 1; markerSizesProp.arraySize = 1; TrackingItemProperty.FindPropertyRelative("m_TrackedAsGroup").boolValue = true; markerIDsProp.GetArrayElementAtIndex(0).intValue = trackedObjectData.CARD_GROUP.GroupID; markerSizesProp.GetArrayElementAtIndex(0).floatValue = trackedObjectData.CARD_GROUP.MarkersSize[0]; } //Copy data: dataProp.arraySize = data.Length; for (int i = 0; i < data.Length; i++) { dataProp.GetArrayElementAtIndex(i).intValue = data[i]; } serializedObject.ApplyModifiedProperties(); RefreshJsonItems(); } } } break; } } bool IsValidTrackingJson(UnityEngine.Object candidate, out TrackedObjectJsonEditor trackedObjectData, out byte[] data) { trackedObjectData = null; data = null; foreach (var item in this.mTarget.trackingItems) { if (item != null && item.JSONConfig == candidate) { Debug.LogFormat("[RhinoX] Json tracking profile : {0} has already been added !", candidate.name); return false; } } bool isJson = false; try { string jsonAssetPath = AssetDatabase.GetAssetPath(candidate); string txt = File.ReadAllText(AssetDatabase.GetAssetPath(candidate)); TrackedObjectJsonEditor tJson = JsonUtility.FromJson(txt); trackedObjectData = tJson; //Get data: string dataAssetPath = Path.Combine(Path.GetDirectoryName(jsonAssetPath), Path.GetFileNameWithoutExtension(jsonAssetPath) + ".dat"); if (File.Exists(dataAssetPath)) { var bytes = File.ReadAllBytes(dataAssetPath); data = bytes; } isJson = true; } catch { isJson = false; } return isJson; } } }