You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			875 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C#
		
	
		
		
			
		
	
	
			875 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C#
		
	
| 
								 
											1 year ago
										 
									 | 
							
								//======= Copyright (c) Valve Corporation, All rights reserved. ===============
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Purpose: Render model of associated tracked object
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//=============================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								using UnityEngine;
							 | 
						||
| 
								 | 
							
								using System.Collections;
							 | 
						||
| 
								 | 
							
								using System.Collections.Generic;
							 | 
						||
| 
								 | 
							
								using System.Runtime.InteropServices;
							 | 
						||
| 
								 | 
							
								using Valve.VR;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace Valve.VR
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    [ExecuteInEditMode]
							 | 
						||
| 
								 | 
							
								    public class SteamVR_RenderModel : MonoBehaviour
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        public SteamVR_TrackedObject.EIndex index = SteamVR_TrackedObject.EIndex.None;
							 | 
						||
| 
								 | 
							
								        protected SteamVR_Input_Sources inputSource;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public const string modelOverrideWarning = "Model override is really only meant to be used in " +
							 | 
						||
| 
								 | 
							
								            "the scene view for lining things up; using it at runtime is discouraged.  Use tracked device " +
							 | 
						||
| 
								 | 
							
								            "index instead to ensure the correct model is displayed for all users.";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Tooltip(modelOverrideWarning)]
							 | 
						||
| 
								 | 
							
								        public string modelOverride;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Tooltip("Shader to apply to model.")]
							 | 
						||
| 
								 | 
							
								        public Shader shader;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Tooltip("Enable to print out when render models are loaded.")]
							 | 
						||
| 
								 | 
							
								        public bool verbose = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Tooltip("If available, break down into separate components instead of loading as a single mesh.")]
							 | 
						||
| 
								 | 
							
								        public bool createComponents = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        [Tooltip("Update transforms of components at runtime to reflect user action.")]
							 | 
						||
| 
								 | 
							
								        public bool updateDynamically = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Additional controller settings for showing scrollwheel, etc.
							 | 
						||
| 
								 | 
							
								        public RenderModel_ControllerMode_State_t controllerModeState;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Name of the sub-object which represents the "local" coordinate space for each component.
							 | 
						||
| 
								 | 
							
								        public const string k_localTransformName = "attach";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Cached name of this render model for updating component transforms at runtime.
							 | 
						||
| 
								 | 
							
								        public string renderModelName { get; private set; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public bool initializedAttachPoints { get; set; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private Dictionary<string, Transform> componentAttachPoints = new Dictionary<string, Transform>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private List<MeshRenderer> meshRenderers = new List<MeshRenderer>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // If someone knows how to keep these from getting cleaned up every time
							 | 
						||
| 
								 | 
							
								        // you exit play mode, let me know.  I've tried marking the RenderModel
							 | 
						||
| 
								 | 
							
								        // class below as [System.Serializable] and switching to normal public
							 | 
						||
| 
								 | 
							
								        // variables for mesh and material to get them to serialize properly,
							 | 
						||
| 
								 | 
							
								        // as well as tried marking the mesh and material objects as
							 | 
						||
| 
								 | 
							
								        // DontUnloadUnusedAsset, but Unity was still unloading them.
							 | 
						||
| 
								 | 
							
								        // The hashtable is preserving its entries, but the mesh and material
							 | 
						||
| 
								 | 
							
								        // variables are going null.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public class RenderModel
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            public RenderModel(Mesh mesh, Material material)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                this.mesh = mesh;
							 | 
						||
| 
								 | 
							
								                this.material = material;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            public Mesh mesh { get; private set; }
							 | 
						||
| 
								 | 
							
								            public Material material { get; private set; }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public static Hashtable models = new Hashtable();
							 | 
						||
| 
								 | 
							
								        public static Hashtable materials = new Hashtable();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        // Helper class to load render models interface on demand and clean up when done.
							 | 
						||
| 
								 | 
							
								        public sealed class RenderModelInterfaceHolder : System.IDisposable
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            private bool needsShutdown, failedLoadInterface;
							 | 
						||
| 
								 | 
							
								            private CVRRenderModels _instance;
							 | 
						||
| 
								 | 
							
								            public CVRRenderModels instance
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                get
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    if (_instance == null && !failedLoadInterface)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        if (Application.isEditor && Application.isPlaying == false)
							 | 
						||
| 
								 | 
							
								                            needsShutdown = SteamVR.InitializeTemporarySession();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        _instance = OpenVR.RenderModels;
							 | 
						||
| 
								 | 
							
								                        if (_instance == null)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            Debug.LogError("<b>[SteamVR]</b> Failed to load IVRRenderModels interface version " + OpenVR.IVRRenderModels_Version);
							 | 
						||
| 
								 | 
							
								                            failedLoadInterface = true;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    return _instance;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            public void Dispose()
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (needsShutdown)
							 | 
						||
| 
								 | 
							
								                    SteamVR.ExitTemporarySession();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void OnModelSkinSettingsHaveChanged(VREvent_t vrEvent)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (!string.IsNullOrEmpty(renderModelName))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                renderModelName = "";
							 | 
						||
| 
								 | 
							
								                UpdateModel();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void SetMeshRendererState(bool state)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            for (int rendererIndex = 0; rendererIndex < meshRenderers.Count; rendererIndex++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                MeshRenderer renderer = meshRenderers[rendererIndex];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (renderer != null)
							 | 
						||
| 
								 | 
							
								                    renderer.enabled = state;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void OnHideRenderModels(bool hidden)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            SetMeshRendererState(!hidden);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void OnDeviceConnected(int i, bool connected)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (i != (int)index)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (connected)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                UpdateModel();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void UpdateModel()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var system = OpenVR.System;
							 | 
						||
| 
								 | 
							
								            if (system == null || index == SteamVR_TrackedObject.EIndex.None)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var error = ETrackedPropertyError.TrackedProp_Success;
							 | 
						||
| 
								 | 
							
								            var capacity = system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, null, 0, ref error);
							 | 
						||
| 
								 | 
							
								            if (capacity <= 1)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Debug.LogError("<b>[SteamVR]</b> Failed to get render model name for tracked object " + index);
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var buffer = new System.Text.StringBuilder((int)capacity);
							 | 
						||
| 
								 | 
							
								            system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, buffer, capacity, ref error);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var s = buffer.ToString();
							 | 
						||
| 
								 | 
							
								            if (renderModelName != s)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                StartCoroutine(SetModelAsync(s));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        IEnumerator SetModelAsync(string newRenderModelName)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            meshRenderers.Clear();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (string.IsNullOrEmpty(newRenderModelName))
							 | 
						||
| 
								 | 
							
								                yield break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Preload all render models before asking for the data to create meshes.
							 | 
						||
| 
								 | 
							
								            using (RenderModelInterfaceHolder holder = new RenderModelInterfaceHolder())
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                CVRRenderModels renderModels = holder.instance;
							 | 
						||
| 
								 | 
							
								                if (renderModels == null)
							 | 
						||
| 
								 | 
							
								                    yield break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Gather names of render models to preload.
							 | 
						||
| 
								 | 
							
								                string[] renderModelNames;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                uint count = renderModels.GetComponentCount(newRenderModelName);
							 | 
						||
| 
								 | 
							
								                if (count > 0)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    renderModelNames = new string[count];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    for (int componentIndex = 0; componentIndex < count; componentIndex++)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        uint capacity = renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, null, 0);
							 | 
						||
| 
								 | 
							
								                        if (capacity == 0)
							 | 
						||
| 
								 | 
							
								                            continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var componentNameStringBuilder = new System.Text.StringBuilder((int)capacity);
							 | 
						||
| 
								 | 
							
								                        if (renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, componentNameStringBuilder, capacity) == 0)
							 | 
						||
| 
								 | 
							
								                            continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        string componentName = componentNameStringBuilder.ToString();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        capacity = renderModels.GetComponentRenderModelName(newRenderModelName, componentName, null, 0);
							 | 
						||
| 
								 | 
							
								                        if (capacity == 0)
							 | 
						||
| 
								 | 
							
								                            continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var nameStringBuilder = new System.Text.StringBuilder((int)capacity);
							 | 
						||
| 
								 | 
							
								                        if (renderModels.GetComponentRenderModelName(newRenderModelName, componentName, nameStringBuilder, capacity) == 0)
							 | 
						||
| 
								 | 
							
								                            continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var s = nameStringBuilder.ToString();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        // Only need to preload if not already cached.
							 | 
						||
| 
								 | 
							
								                        RenderModel model = models[s] as RenderModel;
							 | 
						||
| 
								 | 
							
								                        if (model == null || model.mesh == null)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            renderModelNames[componentIndex] = s;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    // Only need to preload if not already cached.
							 | 
						||
| 
								 | 
							
								                    RenderModel model = models[newRenderModelName] as RenderModel;
							 | 
						||
| 
								 | 
							
								                    if (model == null || model.mesh == null)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        renderModelNames = new string[] { newRenderModelName };
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        renderModelNames = new string[0];
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Keep trying every 100ms until all components finish loading.
							 | 
						||
| 
								 | 
							
								                while (true)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var loading = false;
							 | 
						||
| 
								 | 
							
								                    for (int renderModelNameIndex = 0; renderModelNameIndex < renderModelNames.Length; renderModelNameIndex++)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        if (string.IsNullOrEmpty(renderModelNames[renderModelNameIndex]))
							 | 
						||
| 
								 | 
							
								                            continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var pRenderModel = System.IntPtr.Zero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var error = renderModels.LoadRenderModel_Async(renderModelNames[renderModelNameIndex], ref pRenderModel);
							 | 
						||
| 
								 | 
							
								                        //Debug.Log("<b>[SteamVR]</b> renderModels.LoadRenderModel_Async(" + renderModelNames[renderModelNameIndex] + ": " + error.ToString());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        if (error == EVRRenderModelError.Loading)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            loading = true;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                        else if (error == EVRRenderModelError.None)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            // Preload textures as well.
							 | 
						||
| 
								 | 
							
								                            var renderModel = MarshalRenderModel(pRenderModel);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                            // Check the cache first.
							 | 
						||
| 
								 | 
							
								                            var material = materials[renderModel.diffuseTextureId] as Material;
							 | 
						||
| 
								 | 
							
								                            if (material == null || material.mainTexture == null)
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                var pDiffuseTexture = System.IntPtr.Zero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                                error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
							 | 
						||
| 
								 | 
							
								                                //Debug.Log("<b>[SteamVR]</b> renderModels.LoadRenderModel_Async(" + renderModelNames[renderModelNameIndex] + ": " + error.ToString());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                                if (error == EVRRenderModelError.Loading)
							 | 
						||
| 
								 | 
							
								                                {
							 | 
						||
| 
								 | 
							
								                                    loading = true;
							 | 
						||
| 
								 | 
							
								                                }
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    if (loading)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        yield return new WaitForSecondsRealtime(0.1f);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            bool success = SetModel(newRenderModelName);
							 | 
						||
| 
								 | 
							
								            this.renderModelName = newRenderModelName;
							 | 
						||
| 
								 | 
							
								            SteamVR_Events.RenderModelLoaded.Send(this, success);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private bool SetModel(string renderModelName)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            StripMesh(gameObject);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            using (var holder = new RenderModelInterfaceHolder())
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                if (createComponents)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    componentAttachPoints.Clear();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    if (LoadComponents(holder, renderModelName))
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        UpdateComponents(holder.instance);
							 | 
						||
| 
								 | 
							
								                        return true;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    Debug.Log("<b>[SteamVR]</b> [" + gameObject.name + "] Render model does not support components, falling back to single mesh.");
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (!string.IsNullOrEmpty(renderModelName))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var model = models[renderModelName] as RenderModel;
							 | 
						||
| 
								 | 
							
								                    if (model == null || model.mesh == null)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        var renderModels = holder.instance;
							 | 
						||
| 
								 | 
							
								                        if (renderModels == null)
							 | 
						||
| 
								 | 
							
								                            return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        if (verbose)
							 | 
						||
| 
								 | 
							
								                            Debug.Log("<b>[SteamVR]</b> Loading render model " + renderModelName);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        model = LoadRenderModel(renderModels, renderModelName, renderModelName);
							 | 
						||
| 
								 | 
							
								                        if (model == null)
							 | 
						||
| 
								 | 
							
								                            return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        models[renderModelName] = model;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
							 | 
						||
| 
								 | 
							
								                    MeshRenderer newRenderer = gameObject.AddComponent<MeshRenderer>();
							 | 
						||
| 
								 | 
							
								                    newRenderer.sharedMaterial = model.material;
							 | 
						||
| 
								 | 
							
								                    meshRenderers.Add(newRenderer);
							 | 
						||
| 
								 | 
							
								                    return true;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        RenderModel LoadRenderModel(CVRRenderModels renderModels, string renderModelName, string baseName)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var pRenderModel = System.IntPtr.Zero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            EVRRenderModelError error;
							 | 
						||
| 
								 | 
							
								            while (true)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                error = renderModels.LoadRenderModel_Async(renderModelName, ref pRenderModel);
							 | 
						||
| 
								 | 
							
								                if (error != EVRRenderModelError.Loading)
							 | 
						||
| 
								 | 
							
								                    break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                Sleep();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (error != EVRRenderModelError.None)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Debug.LogError(string.Format("<b>[SteamVR]</b> Failed to load render model {0} - {1}", renderModelName, error.ToString()));
							 | 
						||
| 
								 | 
							
								                return null;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var renderModel = MarshalRenderModel(pRenderModel);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var vertices = new Vector3[renderModel.unVertexCount];
							 | 
						||
| 
								 | 
							
								            var normals = new Vector3[renderModel.unVertexCount];
							 | 
						||
| 
								 | 
							
								            var uv = new Vector2[renderModel.unVertexCount];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var type = typeof(RenderModel_Vertex_t);
							 | 
						||
| 
								 | 
							
								            for (int iVert = 0; iVert < renderModel.unVertexCount; iVert++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var ptr = new System.IntPtr(renderModel.rVertexData.ToInt64() + iVert * Marshal.SizeOf(type));
							 | 
						||
| 
								 | 
							
								                var vert = (RenderModel_Vertex_t)Marshal.PtrToStructure(ptr, type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                vertices[iVert] = new Vector3(vert.vPosition.v0, vert.vPosition.v1, -vert.vPosition.v2);
							 | 
						||
| 
								 | 
							
								                normals[iVert] = new Vector3(vert.vNormal.v0, vert.vNormal.v1, -vert.vNormal.v2);
							 | 
						||
| 
								 | 
							
								                uv[iVert] = new Vector2(vert.rfTextureCoord0, vert.rfTextureCoord1);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            int indexCount = (int)renderModel.unTriangleCount * 3;
							 | 
						||
| 
								 | 
							
								            var indices = new short[indexCount];
							 | 
						||
| 
								 | 
							
								            Marshal.Copy(renderModel.rIndexData, indices, 0, indices.Length);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var triangles = new int[indexCount];
							 | 
						||
| 
								 | 
							
								            for (int iTri = 0; iTri < renderModel.unTriangleCount; iTri++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                triangles[iTri * 3 + 0] = (int)indices[iTri * 3 + 2];
							 | 
						||
| 
								 | 
							
								                triangles[iTri * 3 + 1] = (int)indices[iTri * 3 + 1];
							 | 
						||
| 
								 | 
							
								                triangles[iTri * 3 + 2] = (int)indices[iTri * 3 + 0];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var mesh = new Mesh();
							 | 
						||
| 
								 | 
							
								            mesh.vertices = vertices;
							 | 
						||
| 
								 | 
							
								            mesh.normals = normals;
							 | 
						||
| 
								 | 
							
								            mesh.uv = uv;
							 | 
						||
| 
								 | 
							
								            mesh.triangles = triangles;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
							 | 
						||
| 
								 | 
							
								            mesh.Optimize();
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								            //mesh.hideFlags = HideFlags.DontUnloadUnusedAsset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Check cache before loading texture.
							 | 
						||
| 
								 | 
							
								            var material = materials[renderModel.diffuseTextureId] as Material;
							 | 
						||
| 
								 | 
							
								            if (material == null || material.mainTexture == null)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var pDiffuseTexture = System.IntPtr.Zero;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                while (true)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
							 | 
						||
| 
								 | 
							
								                    if (error != EVRRenderModelError.Loading)
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    Sleep();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (error == EVRRenderModelError.None)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var diffuseTexture = MarshalRenderModel_TextureMap(pDiffuseTexture);
							 | 
						||
| 
								 | 
							
								                    var texture = new Texture2D(diffuseTexture.unWidth, diffuseTexture.unHeight, TextureFormat.RGBA32, false);
							 | 
						||
| 
								 | 
							
								                    if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        texture.Apply();
							 | 
						||
| 
								 | 
							
								                        System.IntPtr texturePointer = texture.GetNativeTexturePtr();
							 | 
						||
| 
								 | 
							
								                        while (true)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            error = renderModels.LoadIntoTextureD3D11_Async(renderModel.diffuseTextureId, texturePointer);
							 | 
						||
| 
								 | 
							
								                            if (error != EVRRenderModelError.Loading)
							 | 
						||
| 
								 | 
							
								                                break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                            Sleep();
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        var textureMapData = new byte[diffuseTexture.unWidth * diffuseTexture.unHeight * 4]; // RGBA
							 | 
						||
| 
								 | 
							
								                        Marshal.Copy(diffuseTexture.rubTextureMapData, textureMapData, 0, textureMapData.Length);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var colors = new Color32[diffuseTexture.unWidth * diffuseTexture.unHeight];
							 | 
						||
| 
								 | 
							
								                        int iColor = 0;
							 | 
						||
| 
								 | 
							
								                        for (int iHeight = 0; iHeight < diffuseTexture.unHeight; iHeight++)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            for (int iWidth = 0; iWidth < diffuseTexture.unWidth; iWidth++)
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                var r = textureMapData[iColor++];
							 | 
						||
| 
								 | 
							
								                                var g = textureMapData[iColor++];
							 | 
						||
| 
								 | 
							
								                                var b = textureMapData[iColor++];
							 | 
						||
| 
								 | 
							
								                                var a = textureMapData[iColor++];
							 | 
						||
| 
								 | 
							
								                                colors[iHeight * diffuseTexture.unWidth + iWidth] = new Color32(r, g, b, a);
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        texture.SetPixels32(colors);
							 | 
						||
| 
								 | 
							
								                        texture.Apply();
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if UNITY_URP
							 | 
						||
| 
								 | 
							
								                    material = new Material(shader != null ? shader : Shader.Find("Universal Render Pipeline/Lit"));
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								                    material = new Material(shader != null ? shader : Shader.Find("Standard"));
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    material.mainTexture = texture;
							 | 
						||
| 
								 | 
							
								                    //material.hideFlags = HideFlags.DontUnloadUnusedAsset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    materials[renderModel.diffuseTextureId] = material;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    renderModels.FreeTexture(pDiffuseTexture);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    Debug.Log("<b>[SteamVR]</b> Failed to load render model texture for render model " + renderModelName + ". Error: " + error.ToString());
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Delay freeing when we can since we'll often get multiple requests for the same model right
							 | 
						||
| 
								 | 
							
								            // after another (e.g. two controllers or two basestations).
							 | 
						||
| 
								 | 
							
								#if UNITY_EDITOR
							 | 
						||
| 
								 | 
							
								            if (!Application.isPlaying)
							 | 
						||
| 
								 | 
							
								                renderModels.FreeRenderModel(pRenderModel);
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								                StartCoroutine(FreeRenderModel(pRenderModel));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return new RenderModel(mesh, material);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        IEnumerator FreeRenderModel(System.IntPtr pRenderModel)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            yield return new WaitForSeconds(1.0f);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            using (var holder = new RenderModelInterfaceHolder())
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var renderModels = holder.instance;
							 | 
						||
| 
								 | 
							
								                renderModels.FreeRenderModel(pRenderModel);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public Transform FindTransformByName(string componentName, Transform inTransform = null)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (inTransform == null)
							 | 
						||
| 
								 | 
							
								                inTransform = this.transform;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (int childIndex = 0; childIndex < inTransform.childCount; childIndex++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Transform child = inTransform.GetChild(childIndex);
							 | 
						||
| 
								 | 
							
								                if (child.name == componentName)
							 | 
						||
| 
								 | 
							
								                    return child;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return null;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public Transform GetComponentTransform(string componentName)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (componentName == null)
							 | 
						||
| 
								 | 
							
								                return this.transform;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (componentAttachPoints.ContainsKey(componentName))
							 | 
						||
| 
								 | 
							
								                return componentAttachPoints[componentName];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return null;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private void StripMesh(GameObject go)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            var meshRenderer = go.GetComponent<MeshRenderer>();
							 | 
						||
| 
								 | 
							
								            if (meshRenderer != null)
							 | 
						||
| 
								 | 
							
								                DestroyImmediate(meshRenderer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var meshFilter = go.GetComponent<MeshFilter>();
							 | 
						||
| 
								 | 
							
								            if (meshFilter != null)
							 | 
						||
| 
								 | 
							
								                DestroyImmediate(meshFilter);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private bool LoadComponents(RenderModelInterfaceHolder holder, string renderModelName)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            // Disable existing components (we will re-enable them if referenced by this new model).
							 | 
						||
| 
								 | 
							
								            // Also strip mesh filter and renderer since these will get re-added if the new component needs them.
							 | 
						||
| 
								 | 
							
								            var t = transform;
							 | 
						||
| 
								 | 
							
								            for (int childIndex = 0; childIndex < t.childCount; childIndex++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var child = t.GetChild(childIndex);
							 | 
						||
| 
								 | 
							
								                child.gameObject.SetActive(false);
							 | 
						||
| 
								 | 
							
								                StripMesh(child.gameObject);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // If no model specified, we're done; return success.
							 | 
						||
| 
								 | 
							
								            if (string.IsNullOrEmpty(renderModelName))
							 | 
						||
| 
								 | 
							
								                return true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var renderModels = holder.instance;
							 | 
						||
| 
								 | 
							
								            if (renderModels == null)
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var count = renderModels.GetComponentCount(renderModelName);
							 | 
						||
| 
								 | 
							
								            if (count == 0)
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (int i = 0; i < count; i++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var capacity = renderModels.GetComponentName(renderModelName, (uint)i, null, 0);
							 | 
						||
| 
								 | 
							
								                if (capacity == 0)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                System.Text.StringBuilder componentNameStringBuilder = new System.Text.StringBuilder((int)capacity);
							 | 
						||
| 
								 | 
							
								                if (renderModels.GetComponentName(renderModelName, (uint)i, componentNameStringBuilder, capacity) == 0)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                string componentName = componentNameStringBuilder.ToString();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Create (or reuse) a child object for this component (some components are dynamic and don't have meshes).
							 | 
						||
| 
								 | 
							
								                t = FindTransformByName(componentName);
							 | 
						||
| 
								 | 
							
								                if (t != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    t.gameObject.SetActive(true);
							 | 
						||
| 
								 | 
							
								                    componentAttachPoints[componentName] = FindTransformByName(k_localTransformName, t);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    t = new GameObject(componentName).transform;
							 | 
						||
| 
								 | 
							
								                    t.parent = transform;
							 | 
						||
| 
								 | 
							
								                    t.gameObject.layer = gameObject.layer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    // Also create a child 'attach' object for attaching things.
							 | 
						||
| 
								 | 
							
								                    var attach = new GameObject(k_localTransformName).transform;
							 | 
						||
| 
								 | 
							
								                    attach.parent = t;
							 | 
						||
| 
								 | 
							
								                    attach.localPosition = Vector3.zero;
							 | 
						||
| 
								 | 
							
								                    attach.localRotation = Quaternion.identity;
							 | 
						||
| 
								 | 
							
								                    attach.localScale = Vector3.one;
							 | 
						||
| 
								 | 
							
								                    attach.gameObject.layer = gameObject.layer;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    componentAttachPoints[componentName] = attach;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Reset transform.
							 | 
						||
| 
								 | 
							
								                t.localPosition = Vector3.zero;
							 | 
						||
| 
								 | 
							
								                t.localRotation = Quaternion.identity;
							 | 
						||
| 
								 | 
							
								                t.localScale = Vector3.one;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                capacity = renderModels.GetComponentRenderModelName(renderModelName, componentName, null, 0);
							 | 
						||
| 
								 | 
							
								                if (capacity == 0)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                var componentRenderModelNameStringBuilder = new System.Text.StringBuilder((int)capacity);
							 | 
						||
| 
								 | 
							
								                if (renderModels.GetComponentRenderModelName(renderModelName, componentName, componentRenderModelNameStringBuilder, capacity) == 0)
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                string componentRenderModelName = componentRenderModelNameStringBuilder.ToString();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Check the cache or load into memory.
							 | 
						||
| 
								 | 
							
								                var model = models[componentRenderModelName] as RenderModel;
							 | 
						||
| 
								 | 
							
								                if (model == null || model.mesh == null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    if (verbose)
							 | 
						||
| 
								 | 
							
								                        Debug.Log("<b>[SteamVR]</b> Loading render model " + componentRenderModelName);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    model = LoadRenderModel(renderModels, componentRenderModelName, renderModelName);
							 | 
						||
| 
								 | 
							
								                    if (model == null)
							 | 
						||
| 
								 | 
							
								                        continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    models[componentRenderModelName] = model;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                t.gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
							 | 
						||
| 
								 | 
							
								                MeshRenderer newRenderer = t.gameObject.AddComponent<MeshRenderer>();
							 | 
						||
| 
								 | 
							
								                newRenderer.sharedMaterial = model.material;
							 | 
						||
| 
								 | 
							
								                meshRenderers.Add(newRenderer);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        SteamVR_Events.Action deviceConnectedAction, hideRenderModelsAction, modelSkinSettingsHaveChangedAction;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        SteamVR_RenderModel()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            deviceConnectedAction = SteamVR_Events.DeviceConnectedAction(OnDeviceConnected);
							 | 
						||
| 
								 | 
							
								            hideRenderModelsAction = SteamVR_Events.HideRenderModelsAction(OnHideRenderModels);
							 | 
						||
| 
								 | 
							
								            modelSkinSettingsHaveChangedAction = SteamVR_Events.SystemAction(EVREventType.VREvent_ModelSkinSettingsHaveChanged, OnModelSkinSettingsHaveChanged);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void OnEnable()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								#if UNITY_EDITOR
							 | 
						||
| 
								 | 
							
								            if (!Application.isPlaying)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								            if (!string.IsNullOrEmpty(modelOverride))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Debug.Log("<b>[SteamVR]</b> " + modelOverrideWarning);
							 | 
						||
| 
								 | 
							
								                enabled = false;
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var system = OpenVR.System;
							 | 
						||
| 
								 | 
							
								            if (system != null && system.IsTrackedDeviceConnected((uint)index))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                UpdateModel();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            deviceConnectedAction.enabled = true;
							 | 
						||
| 
								 | 
							
								            hideRenderModelsAction.enabled = true;
							 | 
						||
| 
								 | 
							
								            modelSkinSettingsHaveChangedAction.enabled = true;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        void OnDisable()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								#if UNITY_EDITOR
							 | 
						||
| 
								 | 
							
								            if (!Application.isPlaying)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								            deviceConnectedAction.enabled = false;
							 | 
						||
| 
								 | 
							
								            hideRenderModelsAction.enabled = false;
							 | 
						||
| 
								 | 
							
								            modelSkinSettingsHaveChangedAction.enabled = false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if UNITY_EDITOR
							 | 
						||
| 
								 | 
							
								        Hashtable values;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        void Update()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								#if UNITY_EDITOR
							 | 
						||
| 
								 | 
							
								            if (!Application.isPlaying)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                // See if anything has changed since this gets called whenever anything gets touched.
							 | 
						||
| 
								 | 
							
								                var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                bool modified = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (values == null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    modified = true;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    foreach (var f in fields)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        if (!values.Contains(f))
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            modified = true;
							 | 
						||
| 
								 | 
							
								                            break;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                        var v0 = values[f];
							 | 
						||
| 
								 | 
							
								                        var v1 = f.GetValue(this);
							 | 
						||
| 
								 | 
							
								                        if (v1 != null)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            if (!v1.Equals(v0))
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                modified = true;
							 | 
						||
| 
								 | 
							
								                                break;
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                        else if (v0 != null)
							 | 
						||
| 
								 | 
							
								                        {
							 | 
						||
| 
								 | 
							
								                            modified = true;
							 | 
						||
| 
								 | 
							
								                            break;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (modified)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    if (renderModelName != modelOverride)
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        renderModelName = modelOverride;
							 | 
						||
| 
								 | 
							
								                        SetModel(modelOverride);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    values = new Hashtable();
							 | 
						||
| 
								 | 
							
								                    foreach (var f in fields)
							 | 
						||
| 
								 | 
							
								                        values[f] = f.GetValue(this);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                return; // Do not update transforms (below) when not playing in Editor (to avoid keeping OpenVR running all the time).
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								            // Update component transforms dynamically.
							 | 
						||
| 
								 | 
							
								            if (updateDynamically)
							 | 
						||
| 
								 | 
							
								                UpdateComponents(OpenVR.RenderModels);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Dictionary<int, string> nameCache;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void UpdateComponents(CVRRenderModels renderModels)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if (renderModels == null)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (transform.childCount == 0)
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (nameCache == null)
							 | 
						||
| 
								 | 
							
								                nameCache = new Dictionary<int, string>();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            for (int childIndex = 0; childIndex < transform.childCount; childIndex++)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                Transform child = transform.GetChild(childIndex);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Cache names since accessing an object's name allocates memory.
							 | 
						||
| 
								 | 
							
								                string componentName;
							 | 
						||
| 
								 | 
							
								                if (!nameCache.TryGetValue(child.GetInstanceID(), out componentName))
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    componentName = child.name;
							 | 
						||
| 
								 | 
							
								                    nameCache.Add(child.GetInstanceID(), componentName);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                var componentState = new RenderModel_ComponentState_t();
							 | 
						||
| 
								 | 
							
								                if (!renderModels.GetComponentStateForDevicePath(renderModelName, componentName, SteamVR_Input_Source.GetHandle(inputSource), ref controllerModeState, ref componentState))
							 | 
						||
| 
								 | 
							
								                    continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                child.localPosition = componentState.mTrackingToComponentRenderModel.GetPosition();
							 | 
						||
| 
								 | 
							
								                child.localRotation = componentState.mTrackingToComponentRenderModel.GetRotation();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                Transform attach = null;
							 | 
						||
| 
								 | 
							
								                for (int childChildIndex = 0; childChildIndex < child.childCount; childChildIndex++)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    Transform childChild = child.GetChild(childChildIndex);
							 | 
						||
| 
								 | 
							
								                    int childInstanceID = childChild.GetInstanceID();
							 | 
						||
| 
								 | 
							
								                    string childName;
							 | 
						||
| 
								 | 
							
								                    if (!nameCache.TryGetValue(childInstanceID, out childName))
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        childName = childChild.name;
							 | 
						||
| 
								 | 
							
								                        nameCache.Add(childInstanceID, componentName);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    if (childName == SteamVR_RenderModel.k_localTransformName)
							 | 
						||
| 
								 | 
							
								                        attach = childChild;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (attach != null)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    attach.position = transform.TransformPoint(componentState.mTrackingToComponentLocal.GetPosition());
							 | 
						||
| 
								 | 
							
								                    attach.rotation = transform.rotation * componentState.mTrackingToComponentLocal.GetRotation();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    initializedAttachPoints = true;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                bool visible = (componentState.uProperties & (uint)EVRComponentProperty.IsVisible) != 0;
							 | 
						||
| 
								 | 
							
								                if (visible != child.gameObject.activeSelf)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    child.gameObject.SetActive(visible);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void SetDeviceIndex(int newIndex)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            this.index = (SteamVR_TrackedObject.EIndex)newIndex;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            modelOverride = "";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (enabled)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                UpdateModel();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        public void SetInputSource(SteamVR_Input_Sources newInputSource)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            inputSource = newInputSource;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        private static void Sleep()
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								#if !UNITY_METRO
							 | 
						||
| 
								 | 
							
								            //System.Threading.Thread.SpinWait(1); //faster napping
							 | 
						||
| 
								 | 
							
								            System.Threading.Thread.Sleep(1);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Helper function to handle the inconvenient fact that the packing for RenderModel_t is
							 | 
						||
| 
								 | 
							
								        /// different on Linux/OSX (4) than it is on Windows (8)
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="pRenderModel">native pointer to the RenderModel_t</param>
							 | 
						||
| 
								 | 
							
								        /// <returns></returns>
							 | 
						||
| 
								 | 
							
								        private RenderModel_t MarshalRenderModel(System.IntPtr pRenderModel)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
							 | 
						||
| 
								 | 
							
								                (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var packedModel = (RenderModel_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t_Packed));
							 | 
						||
| 
								 | 
							
								                RenderModel_t model = new RenderModel_t();
							 | 
						||
| 
								 | 
							
								                packedModel.Unpack(ref model);
							 | 
						||
| 
								 | 
							
								                return model;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return (RenderModel_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /// <summary>
							 | 
						||
| 
								 | 
							
								        /// Helper function to handle the inconvenient fact that the packing for RenderModel_TextureMap_t is
							 | 
						||
| 
								 | 
							
								        /// different on Linux/OSX (4) than it is on Windows (8)
							 | 
						||
| 
								 | 
							
								        /// </summary>
							 | 
						||
| 
								 | 
							
								        /// <param name="pRenderModel">native pointer to the RenderModel_TextureMap_t</param>
							 | 
						||
| 
								 | 
							
								        /// <returns></returns>
							 | 
						||
| 
								 | 
							
								        private RenderModel_TextureMap_t MarshalRenderModel_TextureMap(System.IntPtr pRenderModel)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
							 | 
						||
| 
								 | 
							
								                (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                var packedModel = (RenderModel_TextureMap_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t_Packed));
							 | 
						||
| 
								 | 
							
								                RenderModel_TextureMap_t model = new RenderModel_TextureMap_t();
							 | 
						||
| 
								 | 
							
								                packedModel.Unpack(ref model);
							 | 
						||
| 
								 | 
							
								                return model;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            else
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                return (RenderModel_TextureMap_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t));
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |