/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal { using System; using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using System.IO; using UnityEditor; using LitJson; using System.Text; #endif /// /// A database storing a list of images to be detected and tracked by NRSDK. An image database /// supports up to 1000 images.Only one image database can be in use at any given time. public class NRTrackingImageDatabase : ScriptableObject { /// The images. [SerializeField] private List m_Images = new List(); /// Information describing the raw. [SerializeField] private byte[] m_RawData = null; /// Gets information describing the raw. /// Information describing the raw. public byte[] RawData { get { return m_RawData; } } /// Unique identifier. public string GUID; /// Gets the full pathname of the tracking image data file. /// The full pathname of the tracking image data file. public string TrackingImageDataPath { get { return NRTools.GetTrackingImageDataGenPath() + GUID + "/"; } } /// Gets the full pathname of the tracking image data out put file. /// The full pathname of the tracking image data out put file. public string TrackingImageDataOutPutPath { get { return NRTools.GetTrackingImageDataGenPath(); } } #if UNITY_EDITOR /// True if is raw data dirty, false if not. [SerializeField] private bool m_IsRawDataDirty = true; /// The CLI version. [SerializeField] private string m_CliVersion = string.Empty; /// Gets a value indicating whether this object is CLI updated. /// True if this object is CLI updated, false if not. public bool isCliUpdated { get { string cliBinaryPath; if (!FindCliBinaryPath(out cliBinaryPath)) { return false; } string currentCliVersion; { string error; ShellHelper.RunCommand(cliBinaryPath, "-version", out currentCliVersion, out error); } //NRDebugger.Info("current version:{0} old version:{1}", currentCliVersion, m_CliVersion); bool cliUpdated = m_CliVersion != currentCliVersion; return cliUpdated; } } #endif /// Constructs a new TrackingImageDatabase. public NRTrackingImageDatabase() { #if UNITY_EDITOR GUID = Guid.NewGuid().ToString(); #endif } /// Gets the number of images in the database. /// The count. public int Count { get { lock (m_Images) { return m_Images.Count; } } } /// /// Gets or sets the image at the specified index. You can only modify the database in the /// Unity editor. /// The zero-based index of the image entry to get or set. /// The image entry at index. public NRTrackingImageDatabaseEntry this[int index] { get { lock (m_Images) { return m_Images[index]; } } #if UNITY_EDITOR set { var oldValue = m_Images[index]; m_Images[index] = value; if (oldValue.TextureGUID != m_Images[index].TextureGUID || oldValue.Name != m_Images[index].Name || oldValue.Width != m_Images[index].Width || oldValue.Height != m_Images[index].Height) { m_IsRawDataDirty = true; } EditorUtility.SetDirty(this); } #endif } #if UNITY_EDITOR /// Adds an image entry to the end of the database. /// The image entry to add. public void Add(NRTrackingImageDatabaseEntry entry) { m_Images.Add(entry); EditorUtility.SetDirty(this); } /// Removes an image entry at a specified zero-based index. /// The index of the image entry to remove. public void RemoveAt(int index) { m_Images.RemoveAt(index); EditorUtility.SetDirty(this); } /// Rebuilds the database asset, if needed. public void BuildIfNeeded() { if (!m_IsRawDataDirty) { return; } m_IsRawDataDirty = false; string directory = NRTools.GetTrackingImageDataGenPath() + GUID; if (!Directory.Exists(directory)) { ZipUtility.UnzipFile(RawData, NRTools.GetTrackingImageDataGenPath(), NativeConstants.ZipKey); } //Generate marker data by json file var result_json = TrackingImageDataPath + "markers.json"; if (File.Exists(result_json)) { var json_data = File.ReadAllText(result_json); StringBuilder str = new StringBuilder(); str.AppendLine("# Number of markers"); str.AppendLine(Count.ToString()); DirectoryInfo dir = new DirectoryInfo(directory); var fsinfos = dir.GetDirectories(); string dataPathName = "Data"; if (fsinfos != null && fsinfos.Length > 0) { Array.Sort(fsinfos, (dir1, dir2) => dir1.CreationTime.CompareTo(dir2.CreationTime)); dataPathName = fsinfos[0].Name; } for (int i = 0; i < Count; i++) { var obj = JsonMapper.ToObject(json_data); if (obj != null) { var image_info = obj[this[i].Name]; if (image_info != null) { str.AppendLine(); str.AppendLine(string.Format("./{0}/{1}", dataPathName, this[i].Name)); str.AppendLine("NFT"); str.AppendLine(string.Format("FILTER {0}", image_info["filter"])); str.AppendLine(string.Format("MARKER_WIDTH {0}", image_info["physical_width"])); str.AppendLine(string.Format("MARKER_HEIGHT {0}", image_info["physical_height"])); } } } File.WriteAllText(TrackingImageDataPath + "markers.dat", str.ToString()); } string file_path = directory + "_zipFile"; // Generate zip file ZipUtility.Zip(new string[1] { directory }, file_path, NativeConstants.ZipKey, new ZipUtility.ZipCallback(_result => { m_IsRawDataDirty = _result ? false : true; if (!string.IsNullOrEmpty(file_path) && File.Exists(file_path)) { // Read the zip bytes m_RawData = File.ReadAllBytes(file_path); //NRDebugger.Info("Generate raw data success!" + file_path); //m_IsNeedLoadRawData = false; EditorUtility.SetDirty(this); // Force a save to make certain build process will get updated asset. AssetDatabase.SaveAssets(); } })); UpdateClipVersion(); } /// Updates the clip version. private void UpdateClipVersion() { string cliBinaryPath; if (!FindCliBinaryPath(out cliBinaryPath)) { return; } string currentCliVersion; { string error; ShellHelper.RunCommand(cliBinaryPath, "-version", out currentCliVersion, out error); } //NRDebugger.Info("current version:{0} old version:{1}", currentCliVersion, m_CliVersion); m_CliVersion = currentCliVersion; } /// Gets the image entries that require updating of the image quality score. /// A list of image entries that require updating of the image quality score. public List GetDirtyQualityEntries() { var dirtyEntries = new List(); for (int i = 0; i < m_Images.Count; ++i) { if (!string.IsNullOrEmpty(m_Images[i].Quality)) { continue; } dirtyEntries.Add(m_Images[i]); } if (dirtyEntries.Count == 0) { BuildIfNeeded(); } return dirtyEntries; } /// Gets all entries. /// all entries. public List GetAllEntries() { var allEntries = new List(); for (int i = 0; i < m_Images.Count; ++i) { allEntries.Add(m_Images[i]); } return allEntries; } /// Finds the path to the command-line tool used to generate a database. /// [out] The path to the command-line tool that will be set if a valid path /// was found. /// true if a valid path was found, false otherwise. public static bool FindCliBinaryPath(out string path) { var binaryName = NativeConstants.TrackingImageCliBinary; string[] cliBinaryGuid = AssetDatabase.FindAssets(binaryName); if (cliBinaryGuid.Length == 0) { NRDebugger.Info("Could not find required tool for building TrackingImageDatabase: {0}. " + "Was it removed from the NRSDK?", binaryName); path = string.Empty; return false; } // Remove the '/Assets' from the project path since it will be added in the path below. string projectPath = Application.dataPath.Substring(0, Application.dataPath.Length - 6); path = Path.Combine(projectPath, AssetDatabase.GUIDToAssetPath(cliBinaryGuid[0])); return !string.IsNullOrEmpty(path); } #endif } }