using System; using System.Collections; using System.Runtime.InteropServices; using System.Text; using System.Threading; using UnityEngine; using Valve.VR; [ExecuteInEditMode] public class SteamVR_RenderModel : MonoBehaviour { public string renderModelName { get; private set; } private void OnModelSkinSettingsHaveChanged(params object[] args) { if (!string.IsNullOrEmpty(this.renderModelName)) { this.renderModelName = string.Empty; this.UpdateModel(); } } private void OnHideRenderModels(params object[] args) { bool flag = (bool)args[0]; MeshRenderer component = base.GetComponent(); if (component != null) { component.enabled = !flag; } foreach (MeshRenderer meshRenderer in base.transform.GetComponentsInChildren()) { meshRenderer.enabled = !flag; } } private void OnDeviceConnected(params object[] args) { int num = (int)args[0]; if (num != (int)this.index) { return; } bool flag = (bool)args[1]; if (flag) { this.UpdateModel(); } } public void UpdateModel() { CVRSystem system = OpenVR.System; if (system == null) { return; } ETrackedPropertyError etrackedPropertyError = ETrackedPropertyError.TrackedProp_Success; uint stringTrackedDeviceProperty = system.GetStringTrackedDeviceProperty((uint)this.index, ETrackedDeviceProperty.Prop_RenderModelName_String, null, 0u, ref etrackedPropertyError); if (stringTrackedDeviceProperty <= 1u) { Debug.LogError("Failed to get render model name for tracked object " + this.index); return; } StringBuilder stringBuilder = new StringBuilder((int)stringTrackedDeviceProperty); system.GetStringTrackedDeviceProperty((uint)this.index, ETrackedDeviceProperty.Prop_RenderModelName_String, stringBuilder, stringTrackedDeviceProperty, ref etrackedPropertyError); string text = stringBuilder.ToString(); if (this.renderModelName != text) { this.renderModelName = text; base.StartCoroutine(this.SetModelAsync(text)); } } private IEnumerator SetModelAsync(string renderModelName) { if (string.IsNullOrEmpty(renderModelName)) { yield break; } using (SteamVR_RenderModel.RenderModelInterfaceHolder holder = new SteamVR_RenderModel.RenderModelInterfaceHolder()) { CVRRenderModels renderModels = holder.instance; if (renderModels == null) { yield break; } uint count = renderModels.GetComponentCount(renderModelName); string[] renderModelNames; if (count > 0u) { renderModelNames = new string[count]; int num = 0; while ((long)num < (long)((ulong)count)) { uint num2 = renderModels.GetComponentName(renderModelName, (uint)num, null, 0u); if (num2 != 0u) { StringBuilder stringBuilder = new StringBuilder((int)num2); if (renderModels.GetComponentName(renderModelName, (uint)num, stringBuilder, num2) != 0u) { num2 = renderModels.GetComponentRenderModelName(renderModelName, stringBuilder.ToString(), null, 0u); if (num2 != 0u) { StringBuilder stringBuilder2 = new StringBuilder((int)num2); if (renderModels.GetComponentRenderModelName(renderModelName, stringBuilder.ToString(), stringBuilder2, num2) != 0u) { string text = stringBuilder2.ToString(); SteamVR_RenderModel.RenderModel renderModel = SteamVR_RenderModel.models[text] as SteamVR_RenderModel.RenderModel; if (renderModel == null || renderModel.mesh == null) { renderModelNames[num] = text; } } } } } num++; } } else { SteamVR_RenderModel.RenderModel renderModel2 = SteamVR_RenderModel.models[renderModelName] as SteamVR_RenderModel.RenderModel; if (renderModel2 == null || renderModel2.mesh == null) { renderModelNames = new string[] { renderModelName }; } else { renderModelNames = new string[0]; } } for (;;) { bool loading = false; foreach (string text2 in renderModelNames) { if (!string.IsNullOrEmpty(text2)) { IntPtr zero = IntPtr.Zero; EVRRenderModelError evrrenderModelError = renderModels.LoadRenderModel_Async(text2, ref zero); if (evrrenderModelError == EVRRenderModelError.Loading) { loading = true; } else if (evrrenderModelError == EVRRenderModelError.None) { RenderModel_t renderModel_t = (RenderModel_t)Marshal.PtrToStructure(zero, typeof(RenderModel_t)); Material material = SteamVR_RenderModel.materials[renderModel_t.diffuseTextureId] as Material; if (material == null || material.mainTexture == null) { IntPtr zero2 = IntPtr.Zero; evrrenderModelError = renderModels.LoadTexture_Async(renderModel_t.diffuseTextureId, ref zero2); if (evrrenderModelError == EVRRenderModelError.Loading) { loading = true; } } } } } if (!loading) { break; } yield return new WaitForSeconds(0.1f); } } bool success = this.SetModel(renderModelName); SteamVR_Utils.Event.Send("render_model_loaded", new object[] { this, success }); yield break; } private bool SetModel(string renderModelName) { this.StripMesh(base.gameObject); using (SteamVR_RenderModel.RenderModelInterfaceHolder renderModelInterfaceHolder = new SteamVR_RenderModel.RenderModelInterfaceHolder()) { if (this.createComponents) { if (this.LoadComponents(renderModelInterfaceHolder, renderModelName)) { this.UpdateComponents(); return true; } Debug.Log("[" + base.gameObject.name + "] Render model does not support components, falling back to single mesh."); } if (!string.IsNullOrEmpty(renderModelName)) { SteamVR_RenderModel.RenderModel renderModel = SteamVR_RenderModel.models[renderModelName] as SteamVR_RenderModel.RenderModel; if (renderModel == null || renderModel.mesh == null) { CVRRenderModels instance = renderModelInterfaceHolder.instance; if (instance == null) { return false; } if (this.verbose) { Debug.Log("Loading render model " + renderModelName); } renderModel = this.LoadRenderModel(instance, renderModelName, renderModelName); if (renderModel == null) { return false; } SteamVR_RenderModel.models[renderModelName] = renderModel; } base.gameObject.AddComponent().mesh = renderModel.mesh; base.gameObject.AddComponent().sharedMaterial = renderModel.material; return true; } } return false; } private SteamVR_RenderModel.RenderModel LoadRenderModel(CVRRenderModels renderModels, string renderModelName, string baseName) { IntPtr zero = IntPtr.Zero; EVRRenderModelError evrrenderModelError; for (;;) { evrrenderModelError = renderModels.LoadRenderModel_Async(renderModelName, ref zero); if (evrrenderModelError != EVRRenderModelError.Loading) { break; } Thread.Sleep(1); } if (evrrenderModelError != EVRRenderModelError.None) { Debug.LogError(string.Format("Failed to load render model {0} - {1}", renderModelName, evrrenderModelError.ToString())); return null; } RenderModel_t renderModel_t = (RenderModel_t)Marshal.PtrToStructure(zero, typeof(RenderModel_t)); Vector3[] array = new Vector3[renderModel_t.unVertexCount]; Vector3[] array2 = new Vector3[renderModel_t.unVertexCount]; Vector2[] array3 = new Vector2[renderModel_t.unVertexCount]; Type typeFromHandle = typeof(RenderModel_Vertex_t); int num = 0; while ((long)num < (long)((ulong)renderModel_t.unVertexCount)) { IntPtr ptr = new IntPtr(renderModel_t.rVertexData.ToInt64() + (long)(num * Marshal.SizeOf(typeFromHandle))); RenderModel_Vertex_t renderModel_Vertex_t = (RenderModel_Vertex_t)Marshal.PtrToStructure(ptr, typeFromHandle); array[num] = new Vector3(renderModel_Vertex_t.vPosition.v0, renderModel_Vertex_t.vPosition.v1, -renderModel_Vertex_t.vPosition.v2); array2[num] = new Vector3(renderModel_Vertex_t.vNormal.v0, renderModel_Vertex_t.vNormal.v1, -renderModel_Vertex_t.vNormal.v2); array3[num] = new Vector2(renderModel_Vertex_t.rfTextureCoord0, renderModel_Vertex_t.rfTextureCoord1); num++; } int num2 = (int)(renderModel_t.unTriangleCount * 3u); short[] array4 = new short[num2]; Marshal.Copy(renderModel_t.rIndexData, array4, 0, array4.Length); int[] array5 = new int[num2]; int num3 = 0; while ((long)num3 < (long)((ulong)renderModel_t.unTriangleCount)) { array5[num3 * 3] = (int)array4[num3 * 3 + 2]; array5[num3 * 3 + 1] = (int)array4[num3 * 3 + 1]; array5[num3 * 3 + 2] = (int)array4[num3 * 3]; num3++; } Mesh mesh = new Mesh(); mesh.vertices = array; mesh.normals = array2; mesh.uv = array3; mesh.triangles = array5; Material material = SteamVR_RenderModel.materials[renderModel_t.diffuseTextureId] as Material; if (material == null || material.mainTexture == null) { IntPtr zero2 = IntPtr.Zero; for (;;) { evrrenderModelError = renderModels.LoadTexture_Async(renderModel_t.diffuseTextureId, ref zero2); if (evrrenderModelError != EVRRenderModelError.Loading) { break; } Thread.Sleep(1); } if (evrrenderModelError == EVRRenderModelError.None) { RenderModel_TextureMap_t renderModel_TextureMap_t = (RenderModel_TextureMap_t)Marshal.PtrToStructure(zero2, typeof(RenderModel_TextureMap_t)); Texture2D texture2D = new Texture2D((int)renderModel_TextureMap_t.unWidth, (int)renderModel_TextureMap_t.unHeight, TextureFormat.ARGB32, false); if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL")) { byte[] array6 = new byte[(int)(renderModel_TextureMap_t.unWidth * renderModel_TextureMap_t.unHeight * '\u0004')]; Marshal.Copy(renderModel_TextureMap_t.rubTextureMapData, array6, 0, array6.Length); Color32[] array7 = new Color32[(int)(renderModel_TextureMap_t.unWidth * renderModel_TextureMap_t.unHeight)]; int num4 = 0; for (int i = 0; i < (int)renderModel_TextureMap_t.unHeight; i++) { for (int j = 0; j < (int)renderModel_TextureMap_t.unWidth; j++) { byte r = array6[num4++]; byte g = array6[num4++]; byte b = array6[num4++]; byte a = array6[num4++]; array7[i * (int)renderModel_TextureMap_t.unWidth + j] = new Color32(r, g, b, a); } } texture2D.SetPixels32(array7); texture2D.Apply(); } else { texture2D.Apply(); for (;;) { evrrenderModelError = renderModels.LoadIntoTextureD3D11_Async(renderModel_t.diffuseTextureId, texture2D.GetNativeTexturePtr()); if (evrrenderModelError != EVRRenderModelError.Loading) { break; } Thread.Sleep(1); } } material = new Material((!(this.shader != null)) ? Shader.Find("Standard") : this.shader); material.mainTexture = texture2D; SteamVR_RenderModel.materials[renderModel_t.diffuseTextureId] = material; renderModels.FreeTexture(zero2); } else { Debug.Log("Failed to load render model texture for render model " + renderModelName); } } base.StartCoroutine(this.FreeRenderModel(zero)); return new SteamVR_RenderModel.RenderModel(mesh, material); } private IEnumerator FreeRenderModel(IntPtr pRenderModel) { yield return new WaitForSeconds(1f); using (SteamVR_RenderModel.RenderModelInterfaceHolder renderModelInterfaceHolder = new SteamVR_RenderModel.RenderModelInterfaceHolder()) { CVRRenderModels instance = renderModelInterfaceHolder.instance; instance.FreeRenderModel(pRenderModel); } yield break; } public Transform FindComponent(string componentName) { Transform transform = base.transform; for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); if (child.name == componentName) { return child; } } return null; } private void StripMesh(GameObject go) { MeshRenderer component = go.GetComponent(); if (component != null) { UnityEngine.Object.DestroyImmediate(component); } MeshFilter component2 = go.GetComponent(); if (component2 != null) { UnityEngine.Object.DestroyImmediate(component2); } } private bool LoadComponents(SteamVR_RenderModel.RenderModelInterfaceHolder holder, string renderModelName) { Transform transform = base.transform; for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); child.gameObject.SetActive(false); this.StripMesh(child.gameObject); } if (string.IsNullOrEmpty(renderModelName)) { return true; } CVRRenderModels instance = holder.instance; if (instance == null) { return false; } uint componentCount = instance.GetComponentCount(renderModelName); if (componentCount == 0u) { return false; } int num = 0; while ((long)num < (long)((ulong)componentCount)) { uint num2 = instance.GetComponentName(renderModelName, (uint)num, null, 0u); if (num2 != 0u) { StringBuilder stringBuilder = new StringBuilder((int)num2); if (instance.GetComponentName(renderModelName, (uint)num, stringBuilder, num2) != 0u) { transform = this.FindComponent(stringBuilder.ToString()); if (transform != null) { transform.gameObject.SetActive(true); } else { transform = new GameObject(stringBuilder.ToString()).transform; transform.parent = base.transform; transform.gameObject.layer = base.gameObject.layer; Transform transform2 = new GameObject("attach").transform; transform2.parent = transform; transform2.localPosition = Vector3.zero; transform2.localRotation = Quaternion.identity; transform2.localScale = Vector3.one; transform2.gameObject.layer = base.gameObject.layer; } transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; transform.localScale = Vector3.one; num2 = instance.GetComponentRenderModelName(renderModelName, stringBuilder.ToString(), null, 0u); if (num2 != 0u) { StringBuilder stringBuilder2 = new StringBuilder((int)num2); if (instance.GetComponentRenderModelName(renderModelName, stringBuilder.ToString(), stringBuilder2, num2) != 0u) { SteamVR_RenderModel.RenderModel renderModel = SteamVR_RenderModel.models[stringBuilder2] as SteamVR_RenderModel.RenderModel; if (renderModel == null || renderModel.mesh == null) { if (this.verbose) { Debug.Log("Loading render model " + stringBuilder2); } renderModel = this.LoadRenderModel(instance, stringBuilder2.ToString(), renderModelName); if (renderModel == null) { goto IL_265; } SteamVR_RenderModel.models[stringBuilder2] = renderModel; } transform.gameObject.AddComponent().mesh = renderModel.mesh; transform.gameObject.AddComponent().sharedMaterial = renderModel.material; } } } } IL_265: num++; } return true; } private void OnEnable() { if (!string.IsNullOrEmpty(this.modelOverride)) { Debug.Log("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."); base.enabled = false; return; } CVRSystem system = OpenVR.System; if (system != null && system.IsTrackedDeviceConnected((uint)this.index)) { this.UpdateModel(); } SteamVR_Utils.Event.Listen("device_connected", new SteamVR_Utils.Event.Handler(this.OnDeviceConnected)); SteamVR_Utils.Event.Listen("hide_render_models", new SteamVR_Utils.Event.Handler(this.OnHideRenderModels)); SteamVR_Utils.Event.Listen("ModelSkinSettingsHaveChanged", new SteamVR_Utils.Event.Handler(this.OnModelSkinSettingsHaveChanged)); } private void OnDisable() { SteamVR_Utils.Event.Remove("device_connected", new SteamVR_Utils.Event.Handler(this.OnDeviceConnected)); SteamVR_Utils.Event.Remove("hide_render_models", new SteamVR_Utils.Event.Handler(this.OnHideRenderModels)); SteamVR_Utils.Event.Remove("ModelSkinSettingsHaveChanged", new SteamVR_Utils.Event.Handler(this.OnModelSkinSettingsHaveChanged)); } private void Update() { if (this.updateDynamically) { this.UpdateComponents(); } } public void UpdateComponents() { Transform transform = base.transform; if (transform.childCount == 0) { return; } using (SteamVR_RenderModel.RenderModelInterfaceHolder renderModelInterfaceHolder = new SteamVR_RenderModel.RenderModelInterfaceHolder()) { VRControllerState_t vrcontrollerState_t = (this.index == SteamVR_TrackedObject.EIndex.None) ? default(VRControllerState_t) : SteamVR_Controller.Input((int)this.index).GetState(); for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); CVRRenderModels instance = renderModelInterfaceHolder.instance; if (instance == null) { break; } RenderModel_ComponentState_t renderModel_ComponentState_t = default(RenderModel_ComponentState_t); if (instance.GetComponentState(this.renderModelName, child.name, ref vrcontrollerState_t, ref this.controllerModeState, ref renderModel_ComponentState_t)) { SteamVR_Utils.RigidTransform rigidTransform = new SteamVR_Utils.RigidTransform(renderModel_ComponentState_t.mTrackingToComponentRenderModel); child.localPosition = rigidTransform.pos; child.localRotation = rigidTransform.rot; Transform transform2 = child.Find("attach"); if (transform2 != null) { SteamVR_Utils.RigidTransform rigidTransform2 = new SteamVR_Utils.RigidTransform(renderModel_ComponentState_t.mTrackingToComponentLocal); transform2.position = transform.TransformPoint(rigidTransform2.pos); transform2.rotation = transform.rotation * rigidTransform2.rot; } bool flag = (renderModel_ComponentState_t.uProperties & 2u) != 0u; if (flag != child.gameObject.activeSelf) { child.gameObject.SetActive(flag); } } } } } public void SetDeviceIndex(int index) { this.index = (SteamVR_TrackedObject.EIndex)index; this.modelOverride = string.Empty; if (base.enabled) { this.UpdateModel(); } } public SteamVR_TrackedObject.EIndex index = SteamVR_TrackedObject.EIndex.None; public string modelOverride; public Shader shader; public bool verbose; public bool createComponents = true; public bool updateDynamically = true; public RenderModel_ControllerMode_State_t controllerModeState; public const string k_localTransformName = "attach"; public static Hashtable models = new Hashtable(); public static Hashtable materials = new Hashtable(); 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 sealed class RenderModelInterfaceHolder : IDisposable { public CVRRenderModels instance { get { if (this._instance == null && !this.failedLoadInterface) { if (!SteamVR.active && !SteamVR.usingNativeSupport) { EVRInitError evrinitError = EVRInitError.None; OpenVR.Init(ref evrinitError, EVRApplicationType.VRApplication_Other); this.needsShutdown = true; } this._instance = OpenVR.RenderModels; if (this._instance == null) { Debug.LogError("Failed to load IVRRenderModels interface version IVRRenderModels_005"); this.failedLoadInterface = true; } } return this._instance; } } public void Dispose() { if (this.needsShutdown) { OpenVR.Shutdown(); } } private bool needsShutdown; private bool failedLoadInterface; private CVRRenderModels _instance; } }