Skip to main content
Version: 21 Aug 2024

OpenXRUtils.cs

Source code

// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
// Copyright (c) (2024) Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2
// Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein.
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using MagicLeap.OpenXR.Constants;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.MagicLeap;
using UnityEngine.XR.Management;
using UnityEngine.XR.OpenXR;
using UnityEngine.XR.OpenXR.Features;
using UnityEngine.XR.OpenXR.NativeTypes;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace MagicLeap.OpenXR
{
public static class Utils
{
public static InputDevice FindMagicLeapController(InputDeviceCharacteristics inputDeviceCharacteristics)
{
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(inputDeviceCharacteristics, devices);

// TODO: Consider changing this for loop if the controller bug is fixed.
// Currently, the input device is registered twice and the first element returns zero values.
// This loop searches the list in reverse to get the last element which should have the proper data.
for (int i = devices.Count - 1; i > 0; i--)
{
if (devices[i].name == "Magic Leap Controller OpenXR" && devices[i].isValid)
{
return devices[i];
}
}

return new InputDevice();
}

internal static bool TryGetOpenXRFeature<TFeature>(out TFeature feature) where TFeature : OpenXRFeature
{
feature = null;

var settings = OpenXRSettings.Instance;
if (settings == null)
return false;

feature = settings.GetFeature<TFeature>();
return feature != null;
}

internal static bool TryGetOpenXRLoader(out OpenXRLoader loader)
{
loader = null;
var settings = XRGeneralSettings.Instance;
if (settings == null)
return false;
var mgr = settings.Manager;
if (mgr == null)
return false;
loader = mgr.activeLoader as OpenXRLoader;
return loader != null;
}

internal static bool TryGetSubsytemFromOpenXRLoader<TSubsystem>(out TSubsystem subsystem)
where TSubsystem : class, ISubsystem
{
subsystem = null;
if (!TryGetOpenXRLoader(out var loader))
return false;
subsystem = loader.GetLoadedSubsystem<TSubsystem>();
return subsystem != null;
}

internal static bool DidXrCallSucceed(XrResult result, string functionName = "A native function", Predicate<XrResult> successCase = null, bool showError = true)
{
var success = successCase?.Invoke(result) ?? result == XrResult.Success;

if (success || !showError)
{
return success;
}

var logResult = result.ToString();
if (!Enum.IsDefined(typeof(XrResult), result))
{
logResult = ((MLXrResult)result).ToString();
}
MLPluginLog.ErrorFormat($"{functionName} in the Magic Leap API failed. Reason: {logResult} ");
return false;
}

internal static Vector3 InvertZ(this Vector3 input)
{
return new Vector3(input.x, input.y, -input.z);
}

internal static Quaternion InvertXY(this Quaternion quaternion)
{
return new Quaternion(-quaternion.x, -quaternion.y, quaternion.z, quaternion.w);
}

internal static class OpenXRStructHelpers<T> where T : unmanaged
{

internal static void Create<TType>(TType type, out T result, string typeFieldName = "Type", T defaultValue = default)
where TType: unmanaged
{
var nativeResult = defaultValue;
unsafe
{
var nativePtr = new IntPtr(&nativeResult);
var offset = Marshal.OffsetOf<T>(typeFieldName);
var sourceType = type;
UnsafeUtility.MemCpy((nativePtr + offset.ToInt32()).ToPointer(), &sourceType, sizeof(TType));
result = nativeResult;
}
}
}



#if UNITY_EDITOR
internal static string GetNiceTypeName(System.Type type)
=> UnityEditor.ObjectNames.NicifyVariableName(type.Name);

internal static string GetNiceTypeName<T>()
=> GetNiceTypeName(typeof(T));

private static OpenXRSettings GetSettings(BuildTargetGroup group)
=> OpenXRSettings.GetSettingsForBuildTargetGroup(group);

private static OpenXRFeature GetFeatureForBuildTarget(BuildTargetGroup group, Type featureType)
{
var settings = GetSettings(group);
if (settings == null)
return null;
return settings.GetFeature(featureType);
}

private static TFeature GetFeatureForBuildTarget<TFeature>(BuildTargetGroup group) where TFeature: OpenXRFeature
{
var settings = GetSettings(group);
if (settings == null)
return null;
return settings.GetFeature<TFeature>();
}

internal static bool IsFeatureEnabled(BuildTargetGroup group, Type featureType)
{
var feature = GetFeatureForBuildTarget(group, featureType);
return feature != null && feature.enabled;
}

internal static bool IsFeatureEnabled<TFeature>(BuildTargetGroup group) where TFeature: OpenXRFeature
{
var feature = GetFeatureForBuildTarget<TFeature>(group);
return feature != null && feature.enabled;
}

internal static bool TryEnableFeature(BuildTargetGroup group, Type featureType)
{
var feature = GetFeatureForBuildTarget(group, featureType);
return feature != null && (feature.enabled = true) || false;
}

internal static bool TryEnableFeature<TFeature>(BuildTargetGroup group) where TFeature : OpenXRFeature
{
var feature = GetFeatureForBuildTarget<TFeature>(group);
return feature != null && (feature.enabled = true) || false;
}
#endif // UNITY_EDITOR
}
}