/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal.NREditor { using System.Collections.Generic; using UnityEngine; using UnityEditor; /// Editor for nr trackable image. [CanEditMultipleObjects, CustomEditor(typeof(NRTrackableImageBehaviour))] public class NRTrackableImageEditor : Editor { /// The serialized object. private NRSerializedImageTarget m_SerializedObj; /// The database. private static NRTrackingImageDatabase m_Database; /// Name of the images. private static string[] m_ImagesName; /// imageIndex; private int m_PreSelectOption = -1; /// Executes the 'enable' action. private void OnEnable() { NRTrackableImageBehaviour itb = (NRTrackableImageBehaviour)target; m_SerializedObj = new NRSerializedImageTarget(serializedObject); m_Database = GameObject.FindObjectOfType().SessionConfig.TrackingImageDatabase; if (m_Database == null) return; m_ImagesName = new string[m_Database.Count]; EditorDatabase(itb, m_SerializedObj); } /// Implement this function to make a custom inspector. public override void OnInspectorGUI() { base.OnInspectorGUI(); DrawInspectorGUI(); serializedObject.ApplyModifiedProperties(); } /// Draw inspector graphical user interface. private void DrawInspectorGUI() { if (m_Database == null) { NRDebugger.Error("NRKernalSessionConfig.TrackingImageDatabase is null"); return; } EditorGUI.BeginDisabledGroup(true); EditorGUILayout.Popup("Database", 0, new string[] { m_Database.name }); EditorGUI.EndDisabledGroup(); for (int i = 0; i < m_ImagesName.Length; i++) { m_ImagesName[i] = m_Database[i].Name; } m_SerializedObj.DatabaseIndex = EditorGUILayout.Popup("Image Target", m_SerializedObj.DatabaseIndex, m_ImagesName); if (m_SerializedObj.DatabaseIndex != m_PreSelectOption) { m_PreSelectOption = m_SerializedObj.DatabaseIndex; // todo logic m_SerializedObj.Width = m_Database[m_SerializedObj.DatabaseIndex].Width; m_SerializedObj.Height = m_Database[m_SerializedObj.DatabaseIndex].Width;//Height; UpdateProperties(m_SerializedObj); } if (base.serializedObject.isEditingMultipleObjects) { m_SerializedObj.SerializedObject.ApplyModifiedPropertiesWithoutUndo(); Object[] targetObjs = m_SerializedObj.SerializedObject.targetObjects; for (int i = 0; i < targetObjs.Length; i++) { UpdateAppearance(m_SerializedObj); } } else { UpdateAppearance(m_SerializedObj); } EditorGUI.BeginDisabledGroup(true); EditorGUILayout.PropertyField(m_SerializedObj.WidthProperty, new GUIContent("Width"), new GUILayoutOption[0]); EditorGUILayout.PropertyField(m_SerializedObj.HeightProperty, new GUIContent("Height"), new GUILayoutOption[0]); EditorGUI.EndDisabledGroup(); } /// Editor database. /// The itb. /// The serialized object. public void EditorDatabase(NRTrackableImageBehaviour itb, NRSerializedImageTarget serializedObj) { if (!NREditorSceneManager.Instance.SceneInitialized) { NREditorSceneManager.Instance.InitScene(); } if (!EditorApplication.isPlaying) { CheckMesh(serializedObj); } } /// Updates the properties described by sit. /// The sit. private void UpdateProperties(NRSerializedImageTarget sit) { NRTrackableImageBehaviour itb = ((NRTrackableImageBehaviour)target); itb.TrackableName = m_ImagesName[m_SerializedObj.DatabaseIndex]; itb.DatabaseIndex = m_SerializedObj.DatabaseIndex; } /// Updates the appearance described by serializedImageTarget. /// The serialized image target. private static void UpdateAppearance(NRSerializedImageTarget serializedImageTarget) { UpdateAspectRatio(serializedImageTarget); UpdateScale(serializedImageTarget); UpdateMaterial(serializedImageTarget); } /// Updates the aspect ratio described by it. /// The iterator. internal static void UpdateAspectRatio(NRSerializedImageTarget it) { Vector2 size = new Vector2(it.Width, it.Height); it.AspectRatio = size.y / size.x; using (List.Enumerator enumerator = it.GetBehaviours().GetEnumerator()) { while (enumerator.MoveNext()) { UpdateMesh(enumerator.Current.gameObject, it.AspectRatio); } } } /// Updates the scale described by it. /// The iterator. internal static void UpdateScale(NRSerializedImageTarget it) { Vector2 size = new Vector2(it.Width, it.Height); foreach (NRTrackableImageBehaviour item in it.GetBehaviours()) { if (it.AspectRatio <= 1f) // AspectRatio => y/x { item.transform.localScale = new Vector3(size.x, size.x, size.x) * 0.001f; } else { item.transform.localScale = new Vector3(size.y, size.y, size.y) * 0.001f; } } } /// Updates the material described by sit. /// The sit. internal static void UpdateMaterial(NRSerializedImageTarget sit) { Material mat = sit.GetMaterial(); Material loadMat = LoadMat(); if (mat == null || mat == loadMat) { mat = new Material(loadMat); } string name = m_ImagesName[sit.DatabaseIndex]; Texture2D texture = m_Database[sit.DatabaseIndex].Texture; mat.mainTexture = texture; mat.mainTextureScale = new Vector2(1f, 1f); mat.name = name + "Material"; sit.SetMaterial(mat); } /// Updates the mesh. /// The iterator object. /// The aspect ratio. internal static void UpdateMesh(GameObject itObj, float aspectRatio) { MeshFilter meshFilter = itObj.GetComponent(); if (meshFilter == null) { meshFilter = itObj.AddComponent(); } Vector3 v1, v2, v3, v4; if (aspectRatio <= 1) { v1 = new Vector3(-0.5f, 0f, -aspectRatio * 0.5f); v2 = new Vector3(-0.5f, 0f, aspectRatio * 0.5f); v3 = new Vector3(0.5f, 0f, -aspectRatio * 0.5f); v4 = new Vector3(0.5f, 0f, aspectRatio * 0.5f); } else { float f = 1 / aspectRatio; v1 = new Vector3(-f * 0.5f, 0f, -0.5f); v2 = new Vector3(-f * 0.5f, 0f, 0.5f); v3 = new Vector3(f * 0.5f, 0f, -0.5f); v4 = new Vector3(f * 0.5f, 0f, 0.5f); } Mesh mesh = meshFilter.sharedMesh ?? new Mesh(); mesh.vertices = new Vector3[] { v1, v2, v3, v4 }; mesh.triangles = new int[] { 0, 1, 2, 2, 1, 3 }; mesh.normals = new Vector3[mesh.vertices.Length]; mesh.uv = new Vector2[] { new Vector2(0f, 0f), new Vector2(0f, 1f), new Vector2(1f, 0f), new Vector2(1f, 1f) }; mesh.RecalculateNormals(); meshFilter.sharedMesh = mesh; if (!itObj.GetComponent()) { itObj.AddComponent(); } NREditorSceneManager.Instance.UnloadUnusedAssets(); } /// Check mesh. /// The serialized image target. private void CheckMesh(NRSerializedImageTarget serializedImageTarget) { using (List.Enumerator enumerator = serializedImageTarget.GetBehaviours().GetEnumerator()) { while (enumerator.MoveNext()) { GameObject go = enumerator.Current.gameObject; MeshFilter mf = go.GetComponent(); if ((mf == null || mf.sharedMesh == null) && serializedImageTarget.AspectRatioProperty.hasMultipleDifferentValues) { UpdateMesh(go, serializedImageTarget.AspectRatio); } } } if (!serializedImageTarget.TrackableNameProperty.hasMultipleDifferentValues) { UpdateMaterial(serializedImageTarget); } } /// Loads the matrix. /// The matrix. private static Material LoadMat() { string text = "Assets/NRSDK/Emulator/Materials/DefaultTarget.mat"; Material mat = AssetDatabase.LoadAssetAtPath(text); if (mat == null) { NRDebugger.Error("Could not find reference material at " + text + " please reimport Unity package."); } return mat; } } }