using System; using System.Collections.Generic; using Oculus.Spatializer.Propagation; using UnityEngine; public class ONSPPropagationGeometry : MonoBehaviour { private struct MeshMaterial { public MeshFilter meshFilter; public ONSPPropagationMaterial[] materials; } private struct TerrainMaterial { public Terrain terrain; public ONSPPropagationMaterial[] materials; } public static string GeometryAssetDirectory = "AudioGeometry"; public string filePathRelative = string.Empty; public bool fileEnabled; public bool includeChildMeshes = true; private IntPtr geometryHandle = IntPtr.Zero; public static int OSPSuccess; private static int terrainDecimation = 4; public static string GeometryAssetPath { get { return Application.streamingAssetsPath + "/" + GeometryAssetDirectory; } } public string filePath { get { return GeometryAssetPath + "/" + filePathRelative; } } public static string GetPath(Transform current) { if (current.parent == null) { return current.gameObject.scene.name + "/" + current.name; } return GetPath(current.parent) + "-" + current.name; } private void Awake() { CreatePropagationGeometry(); } private void CreatePropagationGeometry() { if (ONSPPropagation.Interface.CreateAudioGeometry(out geometryHandle) != OSPSuccess) { throw new Exception("Unable to create geometry handle"); } if (filePath != null && filePath.Length != 0 && fileEnabled && Application.isPlaying) { if (!ReadFile()) { Debug.LogError("Failed to read file, attempting to regenerate audio geometry"); UploadGeometry(); } } else { UploadGeometry(); } } private void Update() { if (!(geometryHandle == IntPtr.Zero)) { Matrix4x4 localToWorldMatrix = base.transform.localToWorldMatrix; float[] matrix4x = new float[16] { localToWorldMatrix[0, 0], localToWorldMatrix[1, 0], 0f - localToWorldMatrix[2, 0], localToWorldMatrix[3, 0], localToWorldMatrix[0, 1], localToWorldMatrix[1, 1], 0f - localToWorldMatrix[2, 1], localToWorldMatrix[3, 1], localToWorldMatrix[0, 2], localToWorldMatrix[1, 2], 0f - localToWorldMatrix[2, 2], localToWorldMatrix[3, 2], localToWorldMatrix[0, 3], localToWorldMatrix[1, 3], 0f - localToWorldMatrix[2, 3], localToWorldMatrix[3, 3] }; ONSPPropagation.Interface.AudioGeometrySetTransform(geometryHandle, matrix4x); } } private void OnDestroy() { if (geometryHandle != IntPtr.Zero && ONSPPropagation.Interface.DestroyAudioGeometry(geometryHandle) != OSPSuccess) { throw new Exception("Unable to destroy geometry"); } geometryHandle = IntPtr.Zero; } private static void traverseMeshHierarchy(GameObject obj, ONSPPropagationMaterial[] currentMaterials, bool includeChildren, List meshMaterials, List terrainMaterials, bool ignoreStatic) { if (!obj.activeInHierarchy) { return; } MeshFilter[] components = obj.GetComponents(); Terrain[] components2 = obj.GetComponents(); ONSPPropagationMaterial[] components3 = obj.GetComponents(); if (components3 != null && components3.Length > 0) { int num = components3.Length; if (currentMaterials != null) { num = Math.Max(num, currentMaterials.Length); } ONSPPropagationMaterial[] array = new ONSPPropagationMaterial[num]; if (currentMaterials != null) { for (int i = components3.Length; i < num; i++) { array[i] = currentMaterials[i]; } } currentMaterials = array; for (int j = 0; j < components3.Length; j++) { currentMaterials[j] = components3[j]; } } MeshFilter[] array2 = components; foreach (MeshFilter meshFilter in array2) { Mesh sharedMesh = meshFilter.sharedMesh; if (!(sharedMesh == null)) { if (ignoreStatic && !sharedMesh.isReadable) { Debug.Log("Mesh: " + meshFilter.gameObject.name + " not readable, cannot be static."); continue; } meshMaterials.Add(new MeshMaterial { meshFilter = meshFilter, materials = currentMaterials }); } } Terrain[] array3 = components2; foreach (Terrain terrain in array3) { terrainMaterials.Add(new TerrainMaterial { terrain = terrain, materials = currentMaterials }); } if (!includeChildren) { return; } foreach (Transform item in obj.transform) { if (item.GetComponent() == null) { traverseMeshHierarchy(item.gameObject, currentMaterials, includeChildren, meshMaterials, terrainMaterials, ignoreStatic); } } } private int uploadMesh(IntPtr geometryHandle, GameObject meshObject, Matrix4x4 worldToLocal, bool ignoreStatic) { List list = new List(); List list2 = new List(); traverseMeshHierarchy(meshObject, null, includeChildMeshes, list, list2, ignoreStatic); int num = 0; uint num2 = 0u; int num3 = 0; int num4 = 0; foreach (MeshMaterial item in list) { Mesh sharedMesh = item.meshFilter.sharedMesh; num4 += sharedMesh.subMeshCount; num += sharedMesh.vertexCount; for (int i = 0; i < sharedMesh.subMeshCount; i++) { MeshTopology topology = sharedMesh.GetTopology(i); if (topology == MeshTopology.Triangles || topology == MeshTopology.Quads) { uint indexCount = sharedMesh.GetIndexCount(i); num2 += indexCount; switch (topology) { case MeshTopology.Triangles: num3 += (int)indexCount / 3; break; case MeshTopology.Quads: num3 += (int)indexCount / 4; break; } } } } foreach (TerrainMaterial item2 in list2) { TerrainData terrainData = item2.terrain.terrainData; int heightmapWidth = terrainData.heightmapWidth; int heightmapHeight = terrainData.heightmapHeight; int num5 = (heightmapWidth - 1) / terrainDecimation + 1; int num6 = (heightmapHeight - 1) / terrainDecimation + 1; int num7 = num5 * num6; int num8 = (num5 - 1) * (num6 - 1) * 6; num4++; num += num7; num2 += (uint)num8; num3 += num8 / 3; } List list3 = new List(); List list4 = new List(); MeshGroup[] array = new MeshGroup[num4]; float[] array2 = new float[num * 3]; int[] array3 = new int[num2]; int num9 = 0; int num10 = 0; int num11 = 0; foreach (MeshMaterial item3 in list) { MeshFilter meshFilter = item3.meshFilter; Mesh sharedMesh2 = meshFilter.sharedMesh; Matrix4x4 matrix4x = worldToLocal * meshFilter.gameObject.transform.localToWorldMatrix; list3.Clear(); sharedMesh2.GetVertices(list3); int count = list3.Count; for (int j = 0; j < count; j++) { Vector3 vector = matrix4x.MultiplyPoint3x4(list3[j]); int num12 = (num9 + j) * 3; array2[num12] = vector.x; array2[num12 + 1] = vector.y; array2[num12 + 2] = vector.z; } for (int k = 0; k < sharedMesh2.subMeshCount; k++) { MeshTopology topology2 = sharedMesh2.GetTopology(k); if (topology2 != MeshTopology.Triangles && topology2 != MeshTopology.Quads) { continue; } list4.Clear(); sharedMesh2.GetIndices(list4, k); int count2 = list4.Count; for (int l = 0; l < count2; l++) { array3[num10 + l] = list4[l] + num9; } switch (topology2) { case MeshTopology.Triangles: array[num11 + k].faceType = FaceType.TRIANGLES; array[num11 + k].faceCount = (UIntPtr)(ulong)(count2 / 3); break; case MeshTopology.Quads: array[num11 + k].faceType = FaceType.QUADS; array[num11 + k].faceCount = (UIntPtr)(ulong)(count2 / 4); break; } array[num11 + k].indexOffset = (UIntPtr)(ulong)num10; if (item3.materials != null && item3.materials.Length != 0) { int num13 = k; if (num13 >= item3.materials.Length) { num13 = item3.materials.Length - 1; } item3.materials[num13].StartInternal(); array[num11 + k].material = item3.materials[num13].materialHandle; } else { array[num11 + k].material = IntPtr.Zero; } num10 += count2; } num9 += count; num11 += sharedMesh2.subMeshCount; } foreach (TerrainMaterial item4 in list2) { TerrainData terrainData2 = item4.terrain.terrainData; Matrix4x4 matrix4x2 = worldToLocal * item4.terrain.gameObject.transform.localToWorldMatrix; int heightmapWidth2 = terrainData2.heightmapWidth; int heightmapHeight2 = terrainData2.heightmapHeight; float[,] heights = terrainData2.GetHeights(0, 0, heightmapWidth2, heightmapHeight2); Vector3 size = terrainData2.size; size = new Vector3(size.x / (float)(heightmapWidth2 - 1) * (float)terrainDecimation, size.y, size.z / (float)(heightmapHeight2 - 1) * (float)terrainDecimation); int num14 = (heightmapWidth2 - 1) / terrainDecimation + 1; int num15 = (heightmapHeight2 - 1) / terrainDecimation + 1; int num16 = num14 * num15; int num17 = (num14 - 1) * (num15 - 1) * 2; array[num11].faceType = FaceType.TRIANGLES; array[num11].faceCount = (UIntPtr)(ulong)num17; array[num11].indexOffset = (UIntPtr)(ulong)num10; if (item4.materials != null && 0 < item4.materials.Length) { item4.materials[0].StartInternal(); array[num11].material = item4.materials[0].materialHandle; } else { array[num11].material = IntPtr.Zero; } for (int m = 0; m < num15; m++) { for (int n = 0; n < num14; n++) { int num18 = (num9 + m * num14 + n) * 3; Vector3 vector2 = matrix4x2.MultiplyPoint3x4(Vector3.Scale(size, new Vector3(m, heights[n * terrainDecimation, m * terrainDecimation], n))); array2[num18] = vector2.x; array2[num18 + 1] = vector2.y; array2[num18 + 2] = vector2.z; } } for (int num19 = 0; num19 < num15 - 1; num19++) { for (int num20 = 0; num20 < num14 - 1; num20++) { array3[num10] = num9 + num19 * num14 + num20; array3[num10 + 1] = num9 + (num19 + 1) * num14 + num20; array3[num10 + 2] = num9 + num19 * num14 + num20 + 1; array3[num10 + 3] = num9 + (num19 + 1) * num14 + num20; array3[num10 + 4] = num9 + (num19 + 1) * num14 + num20 + 1; array3[num10 + 5] = num9 + num19 * num14 + num20 + 1; num10 += 6; } } num9 += num16; num11++; } return ONSPPropagation.Interface.AudioGeometryUploadMeshArrays(geometryHandle, array2, num, array3, array3.Length, array, array.Length); } public void UploadGeometry() { if (uploadMesh(geometryHandle, base.gameObject, base.gameObject.transform.worldToLocalMatrix, true) != OSPSuccess) { throw new Exception("Unable to upload audio mesh geometry"); } } public bool ReadFile() { if (filePath == null || filePath.Length == 0) { Debug.LogError("Invalid mesh file path"); return false; } if (ONSPPropagation.Interface.AudioGeometryReadMeshFile(geometryHandle, filePath) != OSPSuccess) { Debug.LogError("Error reading mesh file " + filePath); return false; } return true; } }