private static void OnFrameCapture(ref FrameCaptureInfoNative info) { OutputNative output = Marshal.PtrToStructure <OutputNative>(info.OutputPtr); ulong id = info.Id; ulong timeStamp = info.TimeStamp; bool marshalFrameData = MLMRCamera.OnFrameCapture != null; MLMRCamera.Frame.ImagePlane[] imagePlanes = new MLMRCamera.Frame.ImagePlane[(uint)output.ImagePlanesCount]; for (int i = 0; i < output.ImagePlanesCount; ++i) { ImagePlaneInfoNative planeNative = output.ImagePlanes[i]; if (byteArraysBuffers.Count <= i && marshalFrameData) { byteArraysBuffers.Add(CircularBuffer <byte[]> .Create(new byte[planeNative.Size], new byte[planeNative.Size], new byte[planeNative.Size])); } imagePlanes[i] = MLMRCamera.Frame.ImagePlane.Create(planeNative.Width, planeNative.Height, planeNative.Stride, planeNative.BytesPerPixel, planeNative.Size, planeNative.Data, (marshalFrameData) ? byteArraysBuffers[i].Get() : null); } MLMRCamera.Frame frame = MLMRCamera.Frame.Create(id, timeStamp, imagePlanes, output.Format); OnFrameCapture_NativeCallbackThread?.Invoke(frame); MLThreadDispatch.ScheduleMain(() => { MLMRCamera.OnFrameCapture?.Invoke(frame); }); }
private static void OnError(MLResult.Code resultCode, IntPtr data) { MLThreadDispatch.ScheduleMain(() => { if (MLMRCamera.IsStarted) { MLMRCamera.OnError?.Invoke(MLResult.Create(resultCode)); } }); }
/// <summary> /// Request the list of detected found objects. /// Callback will never be called while request is still pending. /// </summary> /// <param name="callback"> /// Callback used to report query results. /// Callback MLResult code will never be <c>MLResult.Code.Pending</c>. /// </param> /// <returns> /// MLResult.Result inside callback will be <c>MLResult.Code.Ok</c> if successful. /// MLResult.Result inside callback will be <c>MLResult.Code.InvalidParam</c> if failed due to invalid input parameter. /// MLResult.Result inside callback will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error. /// </returns> public static MLResult GetUniqueObjectLabelsAsync(OnGetUniqueObjectLabelsDelegate callback) { MLThreadDispatch.ScheduleWork(() => { string[] labels; MLResult result = MLResult.Create(MLResult.Code.Ok); if (MLFoundObjects.IsValidInstance()) { MLResult.Code resultCode = NativeBindings.MLFoundObjectGetAvailableLabelsCount(_instance.handle, out uint labelCount); result = MLResult.Create(resultCode); labels = new string[labelCount]; if (MLResult.IsOK(resultCode)) { for (uint i = 0; i < labelCount; ++i) { resultCode = NativeBindings.MLFoundObjectGetUniqueLabel(_instance.handle, i, 20, out string label); if (MLResult.IsOK(resultCode)) { labels[i] = label; } else { MLPluginLog.ErrorFormat("MLFoundObjects.GetUniqueObjectLabels failed getting a unique label. Reason: {0}", MLResult.CodeToString(resultCode)); result = MLResult.Create(MLResult.Code.UnspecifiedFailure, string.Format("MLFoundObjects.GetUniqueObjectLabels failed getting a unique label. Reason: {0}", MLResult.CodeToString(resultCode))); } } } else { MLPluginLog.ErrorFormat("MLFoundObjects.GetUniqueObjectLabels failed getting the unique label count. Reason: {0}", MLResult.CodeToString(resultCode)); result = MLResult.Create(MLResult.Code.UnspecifiedFailure, string.Format("MLFoundObjects.GetUniqueObjectLabels failed getting the unique label count. Reason: {0}", MLResult.CodeToString(resultCode))); } } else { labels = new string[0]; MLPluginLog.ErrorFormat("MLFoundObjects.GetUniqueObjectLabelsAsync failed. Reason: No Instance for MLFoundObjects."); result = MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLFoundObjects.GetUniqueObjectLabelsAsync failed. Reason: No Instance for MLFoundObjects"); } MLThreadDispatch.ScheduleMain(() => { callback?.Invoke(result, labels); }); return(true); }); return(MLResult.Create(MLResult.Code.Ok)); }
private static void OnCaptureComplete(IntPtr data) { if (MLMRCamera.IsStarted) { // Atomic operation, so setting outside main thread should be fine. Instance.isCapturing = false; } MLThreadDispatch.ScheduleMain(() => { if (MLMRCamera.IsStarted) { MLMRCamera.OnCaptureComplete?.Invoke(); } }); }
/// <summary> /// Updates the settings of the found objects tracker. /// </summary> /// <param name="newSettings">The new settings to update the found objects tracker with.</param> /// <param name="callback">The callback to invoke when the settings have been updated or failed doing so.</param> /// <returns> /// MLResult.Result inside callback will be <c>MLResult.Code.Ok</c> if successful. /// MLResult.Result inside callback will be <c>MLResult.Code.InvalidParam</c> if failed due to invalid input parameter. /// MLResult.Result inside callback will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error. /// </returns> public static MLResult UpdateSettingsAsync(Settings newSettings, OnUpdateSettingsDelegate callback = null) { MLResult result = MLResult.Create(MLResult.Code.Ok); MLThreadDispatch.ScheduleWork(() => { if (MLFoundObjects.IsValidInstance()) { NativeBindings.Settings settingsNative = new NativeBindings.Settings(); settingsNative.Data = newSettings; MLResult.Code resultCode = NativeBindings.MLFoundObjectTrackerUpdateSettings(_instance.handle, in settingsNative); if (MLResult.IsOK(resultCode)) { MLThreadDispatch.ScheduleMain(() => { result = MLResult.Create(resultCode); _instance.settings = newSettings; callback?.Invoke(result, _instance.settings); }); } else { MLPluginLog.ErrorFormat("MLFoundObjects.UpdateSettingsAsync failed to update settings. Reason: {0}", MLResult.CodeToString(resultCode)); result = MLResult.Create(MLResult.Code.UnspecifiedFailure, string.Format("MLFoundObjects.UpdateSettingsAsync failed to update settings. Reason: {0}", MLResult.CodeToString(resultCode))); MLThreadDispatch.ScheduleMain(() => { callback?.Invoke(result, _instance.settings); }); } } else { MLPluginLog.ErrorFormat("MLFoundObjects.GetObjects failed. Reason: No Instance for MLFoundObjects"); result = MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLFoundObjects.GetFoundObjects failed. Reason: No Instance for MLFoundObjects"); MLThreadDispatch.ScheduleMain(() => { callback?.Invoke(result, _instance.settings); }); } return(true); }); return(result); }
/// <summary> /// Requests a ray cast with the given query parameters. /// </summary> /// <param name="query">Query parameters describing ray being cast.</param> /// <param name="callback">Delegate which will be called when the result of the ray cast is ready.</param> /// <returns> /// MLResult.Result will be <c>MLResult.Code.Ok</c> if successful. /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if failed due to invalid input parameter. /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error. /// </returns> public static MLResult Raycast(QueryParams query, OnRaycastResultDelegate callback) { try { if (MLRaycast.IsValidInstance()) { if (query == null || callback == null) { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed. Reason: Invalid input parameters."); return(MLResult.Create(MLResult.Code.InvalidParam)); } bool RequestRaycast() { if (MLRaycast.IsValidInstance()) { NativeBindings.MLRaycastQueryNative queryNative = new NativeBindings.MLRaycastQueryNative() { Position = MLConvert.FromUnity(query.Position), Direction = MLConvert.FromUnity(query.Direction, true, false), UpVector = MLConvert.FromUnity(query.UpVector, true, false), Width = query.Width, Height = query.Height, HorizontalFovDegrees = query.HorizontalFovDegrees, CollideWithUnobserved = query.CollideWithUnobserved, }; ulong requestHandle = MagicLeapNativeBindings.InvalidHandle; MLResult.Code resultCode = NativeBindings.MLRaycastRequest(_instance.trackerHandle, ref queryNative, ref requestHandle); if (resultCode != MLResult.Code.Ok) { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed to request a new ray cast. Reason: {0}", MLResult.CodeToString(resultCode)); return(true); } if (requestHandle == MagicLeapNativeBindings.InvalidHandle) { MLPluginLog.Error("MLRaycast.Raycast failed to request a new ray cast. Reason: Request handle is invalid."); return(true); } bool GetRaycastResults() { if (MLRaycast.IsValidInstance()) { NativeBindings.MLRaycastResultNative raycastResult = NativeBindings.MLRaycastResultNative.Create(); resultCode = NativeBindings.MLRaycastGetResult(_instance.trackerHandle, requestHandle, ref raycastResult); if (resultCode == MLResult.Code.Pending) { return(false); } if (resultCode == MLResult.Code.Ok) { // Check if there is a valid hit result. bool didHit = raycastResult.State != ResultState.RequestFailed && raycastResult.State != ResultState.NoCollision; MLThreadDispatch.ScheduleMain(() => { if (MLRaycast.IsValidInstance()) { callback( raycastResult.State, didHit ? MLConvert.ToUnity(raycastResult.Hitpoint) : Vector3.zero, didHit ? MLConvert.ToUnity(raycastResult.Normal, true, false) : Vector3.zero, raycastResult.Confidence); } else { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed. Reason: No Instance for MLRaycast"); } }); } else { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed to get raycast result. Reason: {0}", MLResult.CodeToString(resultCode)); } } else { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed. Reason: No Instance for MLRaycast"); } return(true); } MLThreadDispatch.ScheduleWork(GetRaycastResults); } else { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed. Reason: No Instance for MLRaycast"); } return(true); } MLThreadDispatch.ScheduleWork(RequestRaycast); return(MLResult.Create(MLResult.Code.Ok)); } else { MLPluginLog.ErrorFormat("MLRaycast.Raycast failed. Reason: No Instance for MLRaycast"); return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLRaycast.Raycast failed. Reason: No Instance for MLRaycast")); } } catch (System.EntryPointNotFoundException) { MLPluginLog.Error("MLRaycast.Raycast failed. Reason: API symbols not found"); return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLRaycast.Raycast failed. Reason: API symbols not found")); } }
/// <summary> /// Begin querying for planes. /// </summary> /// <param name="queryParams">All values are required, omitting values may result in unexpected behavior.</param> /// <param name="callback">Callback used to report query results.</param> /// <returns> /// MLResult.Result will be <c>MLResult.Code.Ok</c> if successful. /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if failed due to invalid input parameter. /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error. /// </returns> private MLResult BeginPlaneQuery(QueryParams queryParams, QueryResultsDelegate callback) { try { if (!NativeBindings.MLHandleIsValid(_instance.planesTracker)) { MLPluginLog.Error("MLPlanes.BeginPlaneQuery failed to request planes. Reason: Tracker handle is invalid"); return(MLResult.Create(MLResult.Code.InvalidParam)); } bool BeginQuery() { if (MLPlanes.IsValidInstance()) { NativeBindings.QueryParamsNative planeQuery = new NativeBindings.QueryParamsNative() { Data = queryParams }; ulong queryHandle = MagicLeapNativeBindings.InvalidHandle; MLResult.Code resultCode = NativeBindings.MLPlanesQueryBegin(_instance.planesTracker, ref planeQuery, ref queryHandle); if (resultCode != MLResult.Code.Ok) { MLPluginLog.ErrorFormat("MLPlanes.BeginPlaneQuery failed to request planes. Reason: {0}", MLResult.CodeToString(resultCode)); return(true); } // Create query object to prepresent this newly registered plane query. NativeBindings.Query query = new NativeBindings.Query((QueryResultsDelegate)callback, planeQuery.MaxResults, _instance.IsRequestingBoundaries(planeQuery.Flags)); bool GetPlanesResults() { if (MLPlanes.IsValidInstance()) { // Request the update. resultCode = NativeBindings.MLPlanesQueryGetResultsWithBoundaries(_instance.planesTracker, queryHandle, query.PlanesResultsUnmanaged, out uint numResults, ref query.PlaneBoundariesList); if (resultCode == MLResult.Code.Pending) { return(false); } if (resultCode == MLResult.Code.Ok) { query.ExtractPlanesFromQueryResults(numResults); resultCode = NativeBindings.MLPlanesReleaseBoundariesList(_instance.planesTracker, ref query.PlaneBoundariesList); if (resultCode == MLResult.Code.Ok) { query.Result = MLResult.Create(resultCode); if (query.Planes == null) { query.Planes = new Plane[] { }; } if (query.PlaneBoundaries == null) { query.PlaneBoundaries = new Boundaries[] { }; } MLThreadDispatch.ScheduleMain(() => { if (MLPlanes.IsValidInstance()) { callback(query.Result, query.Planes, query.PlaneBoundaries); } else { MLPluginLog.ErrorFormat("MLPlanes.BeginPlaneQuery failed. Reason: No Instance for MLPlanes"); } }); } else { MLPluginLog.ErrorFormat("MLPlanes.BeginPlaneQuery failed to release boundaries list. Reason: {0}", MLResult.CodeToString(resultCode)); } } else { MLPluginLog.ErrorFormat("MLPlanes.BeginPlaneQuery failed to query planes. Reason: {0}", MLResult.CodeToString(resultCode)); } } else { MLPluginLog.ErrorFormat("MLPlanes.BeginPlaneQuery failed. Reason: No Instance for MLPlanes"); } return(true); } MLThreadDispatch.ScheduleWork(GetPlanesResults); } else { MLPluginLog.ErrorFormat("MLPlanes.BeginPlaneQuery failed. Reason: No Instance for MLPlanes"); } return(true); } MLThreadDispatch.ScheduleWork(BeginQuery); return(MLResult.Create(MLResult.Code.Ok)); } catch (System.EntryPointNotFoundException) { MLPluginLog.Error("MLPlanes.BeginPlaneQuery failed. Reason: API symbols not found"); return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLPlanes.BeginPlaneQuery failed. Reason: API symbols not found")); } }
/// <summary> /// Process pending requests and call the callback specified in the startup config. /// </summary> private void ProcessPendingQueriesAsync() { MLThreadDispatch.ScheduleWork(() => { try { if (_instance.pendingQueries.Count > 0) { // Process each individual pending query to get updated status. foreach (ulong handle in _instance.pendingQueries.Keys) { // Request the update. MLResult.Code resultCode = NativeBindings.MLFoundObjectGetResultCount(_instance.handle, handle, out uint resultCount); if (MLResult.IsOK(resultCode)) { FoundObject[] foundObjects = new FoundObject[resultCount]; // For each found object in the query, get it's reference and property values from the API. for (uint objectIndex = 0; objectIndex < resultCount; objectIndex++) { NativeBindings.FoundObjectNative nativeFoundObject = new NativeBindings.FoundObjectNative(); // Get the object reference from the API. resultCode = NativeBindings.MLFoundObjectGetResult(_instance.handle, handle, objectIndex, ref nativeFoundObject); if (MLResult.IsOK(resultCode)) { Dictionary <string, string> properties = new Dictionary <string, string>(); // Get the object's properties from the API. if (nativeFoundObject.PropertyCount > 0) { NativeBindings.PropertyNative objectProperty = new NativeBindings.PropertyNative(); for (uint propertyIndex = 0; propertyIndex < nativeFoundObject.PropertyCount; propertyIndex++) { resultCode = NativeBindings.MLFoundObjectGetProperty(_instance.handle, nativeFoundObject.Id, propertyIndex, ref objectProperty); if (MLResult.IsOK(resultCode)) { properties.Add(new string(objectProperty.Key).Replace("\0", string.Empty).ToLower(), new string(objectProperty.Value).Replace("\0", string.Empty)); } else { MLPluginLog.ErrorFormat("MLFoundObjects.ProcessPendingQueries failed to get found object property. Reason: {0}", MLResult.CodeToString(resultCode)); } } } FoundObject foundObject = nativeFoundObject.Data; // Currently the only valid object properties are: label, score foundObject.Label = properties.ContainsKey("label") ? properties["label"] : string.Empty; foundObject.Confidence = properties.ContainsKey("score") ? Convert.ToSingle(properties["score"]) : 0f; foundObjects[objectIndex] = foundObject; } else { MLPluginLog.ErrorFormat("MLFoundObjects.ProcessPendingQueries failed to get found object. Reason: {0}", MLResult.CodeToString(resultCode)); _instance.errorQueries.Add(handle); } } if (!_instance.completedQueries.Contains(handle)) { _instance.completedQueries.Add(handle); } Query query = _instance.pendingQueries[handle]; // Dispatch list of found objects back to main. MLThreadDispatch.ScheduleMain(() => { query.Callback(MLResult.Create(resultCode), foundObjects); }); } else { MLPluginLog.ErrorFormat("MLFoundObjects.ProcessPendingQueries failed to query found objects. Reason: {0}", MLResult.CodeToString(resultCode)); _instance.errorQueries.Add(handle); } } foreach (ulong handle in _instance.errorQueries) { _instance.pendingQueries.TryRemove(handle, out Query q); } _instance.errorQueries.Clear(); foreach (ulong handle in _instance.completedQueries) { _instance.pendingQueries.TryRemove(handle, out Query q); } _instance.completedQueries.Clear(); } } catch (System.EntryPointNotFoundException) { MLPluginLog.Error("MLFoundObjects.ProcessPendingQueries failed. Reason: API symbols not found"); } return(true); }); }
/// <summary> /// Returns filtered list of PCFs based on the parameters of the given queryFilter. /// </summary> /// <param name="queryFilter">Parameters used to curate the returned values.</param> /// <param name="callback">Delegate used to return the resulting MLResult.Result and list of found PCFs.</param> /// <param name="update">Determines if the PCFs should have their pose updated.</param> /// <returns> /// MLResult.Result will be <c>MLResult.Code.Ok</c> if all the PCFs from the current map have been found successfully. /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to no API instance being found. /// </returns> public static MLResult FindPCFsByFilter(QueryFilter queryFilter, OnFoundMultiPCFDelegate callback, bool update = true) { List <PCF> pcfList = new List <PCF>(); if (MLPersistentCoordinateFrames.IsValidInstance()) { NativeBindings.QueryFilterNative queryFilterNative = NativeBindings.QueryFilterNative.Create(); queryFilterNative.Data = queryFilter; MLThreadDispatch.ScheduleWork(() => { if (MLPersistentCoordinateFrames.IsValidInstance()) { try { uint numPCFs = 0; MLResult.Code resultCode = NativeBindings.MLPersistentCoordinateFrameGetCount(MLPersistentCoordinateFrames._instance.nativeTracker, ref numPCFs); MagicLeapNativeBindings.MLCoordinateFrameUID[] cfuidArray = new MagicLeapNativeBindings.MLCoordinateFrameUID[numPCFs]; if (MLResult.IsOK(resultCode) && numPCFs > 0) { //// With these conditions the user is asking for all PCFs, no need to use the slower thised query call. if (queryFilter.TypesMask == (PCF.Types.SingleUserSingleSession | PCF.Types.SingleUserMultiSession | PCF.Types.MultiUserMultiSession) && queryFilter.Radius <= 0 && !queryFilter.Sorted) { resultCode = NativeBindings.MLPersistentCoordinateFrameGetAllEx(_instance.nativeTracker, numPCFs, cfuidArray); } else { resultCode = NativeBindings.MLPersistentCoordinateFrameQuery(_instance.nativeTracker, in queryFilterNative, cfuidArray, out uint cfuidCount); } if (!MLResult.IsOK(resultCode)) { if (resultCode == MLResult.Code.PassableWorldLowMapQuality || resultCode == MLResult.Code.PassableWorldUnableToLocalize) { MLPluginLog.WarningFormat("Map quality not sufficient enough for MLPersistentCoordinateFrames.FindPCFsByFilter. Reason: {0}", MLResult.CodeToString(resultCode)); } else { MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: {0}", MLResult.IsOK(resultCode) ? "No PCFs could be found." : MLResult.CodeToString(resultCode)); } return(false); } } else { if (resultCode == MLResult.Code.PassableWorldLowMapQuality || resultCode == MLResult.Code.PassableWorldUnableToLocalize) { MLPluginLog.WarningFormat("Map quality not sufficient enough for MLPersistentCoordinateFrames.FindPCFsByFilter. Reason: {0}", MLResult.CodeToString(resultCode)); } else { MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: {0}", MLResult.IsOK(resultCode) ? "No PCFs could be found." : MLResult.CodeToString(resultCode)); } return(false); } MLThreadDispatch.ScheduleMain(() => { if (MLPersistentCoordinateFrames.IsValidInstance()) { if (MLResult.IsOK(resultCode) && MLPersistentCoordinateFrames.IsLocalized) { for (int i = 0; i < cfuidArray.Length; ++i) { MagicLeapNativeBindings.MLCoordinateFrameUID pcfCFUID = cfuidArray[i]; if (!pcfCFUID.Equals(MagicLeapNativeBindings.MLCoordinateFrameUID.EmptyFrame)) { PCF pcf = null; if (_instance.mapAllPCFs.ContainsKey(pcfCFUID)) { pcf = _instance.mapAllPCFs[pcfCFUID]; if (update) { MLResult result = pcf.Update(); if (!result.IsOk) { MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.FindPCFsByFilter failed to update the found PCF with CFUID {0}, Reason: {1}", pcf.CFUID, result); } } } else { pcf = new PCF(pcfCFUID); _instance.mapAllPCFs.Add(pcfCFUID, pcf); pcf.Update(); } pcfList.Add(pcf); } } } callback?.Invoke(resultCode, pcfList); } else { MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: No Instance for MLPersistentCoordinateFrames."); } }); return(true); } catch (EntryPointNotFoundException) { MLPluginLog.Error("MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: API symbols not found."); callback?.Invoke(MLResult.Code.UnspecifiedFailure, pcfList); return(true); } } else { MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: No Instance for MLPersistentCoordinateFrames."); callback?.Invoke(MLResult.Code.UnspecifiedFailure, pcfList); return(true); } }); return(MLResult.Create(MLResult.Code.Ok)); } else { MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: No Instance for MLPersistentCoordinateFrames."); callback?.Invoke(MLResult.Code.UnspecifiedFailure, pcfList); return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLPersistentCoordinateFrames.FindPCFsByFilter failed. Reason: No Instance for MLPersistentCoordinateFrames.")); } }