// EdenAutoMorpher_ProfileSaver_Script, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Eden.AutoMorpher.profile.ProfileUtils_BVHUtil
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;

public class ProfileUtils_BVHUtil
{
    private const int LeafMaxTriangles = 4;

    public ProfileBVH GetBVHData(Transform rootTransform, List<ProfileBakedBodyMesh> bakedBodyMeshes)
    {
        return this.BuildFromSkinnedMeshes(rootTransform, bakedBodyMeshes);
    }

    public ProfileBVH BuildFromSkinnedMeshes(Transform rootTransform, List<ProfileBakedBodyMesh> bakedBodyMeshes)
    {
        ProfileBVH profileBVH = new ProfileBVH
        {
            vertices = new List<Vector3>(1024)
        };
        int num = 0;
        foreach (ProfileBakedBodyMesh bakedBodyMesh in bakedBodyMeshes)
        {
            if (bakedBodyMesh != null && !(bakedBodyMesh.smr == null) && !(bakedBodyMesh.smr.sharedMesh == null))
            {
                num += bakedBodyMesh.smr.sharedMesh.triangles.Length / 3;
            }
        }
        if (num == 0)
        {
            return null;
        }
        profileBVH.datas = new profileBVHData[num];
        Matrix4x4 worldToLocalMatrix = rootTransform.worldToLocalMatrix;
        int num2 = 0;
        foreach (ProfileBakedBodyMesh bakedBodyMesh2 in bakedBodyMeshes)
        {
            if (bakedBodyMesh2 != null && !(bakedBodyMesh2.smr == null) && !(bakedBodyMesh2.smr.sharedMesh == null))
            {
                int count = profileBVH.vertices.Count;
                for (int i = 0; i < bakedBodyMesh2.worldVertices.Length; i++)
                {
                    Vector3 item = worldToLocalMatrix.MultiplyPoint3x4(bakedBodyMesh2.worldVertices[i]);
                    profileBVH.vertices.Add(item);
                }
                int[] triangles = bakedBodyMesh2.smr.sharedMesh.triangles;
                int num3 = triangles.Length / 3;
                for (int j = 0; j < num3; j++)
                {
                    int num4 = triangles[j * 3];
                    int num5 = triangles[j * 3 + 1];
                    int num6 = triangles[j * 3 + 2];
                    profileBVH.datas[num2++] = new profileBVHData
                    {
                        verA = count + num4,
                        verB = count + num5,
                        verC = count + num6
                    };
                }
            }
        }
        int num7 = num;
        int[] array = new int[num7];
        for (int k = 0; k < num7; k++)
        {
            array[k] = k;
        }
        profileBVH.dataIndices = array;
        List<profileBVHNode> list = new List<profileBVHNode>();
        this.BuildRecursive(profileBVH, array, 0, num7, list);
        profileBVH.nodes = list.ToArray();
        return profileBVH;
    }

    private int BuildRecursive(ProfileBVH bvh, int[] triIndices, int start, int count, List<profileBVHNode> outNodes)
    {
        int count2 = outNodes.Count;
        profileBVHNode profileBVHNode2 = new profileBVHNode();
        Bounds bounds = default(Bounds);
        bool flag = true;
        for (int i = start; i < start + count; i++)
        {
            profileBVHData profileBVHData2 = bvh.datas[triIndices[i]];
            Vector3 vector = bvh.vertices[profileBVHData2.verA];
            Vector3 point = bvh.vertices[profileBVHData2.verB];
            Vector3 point2 = bvh.vertices[profileBVHData2.verC];
            if (flag)
            {
                bounds = new Bounds(vector, Vector3.zero);
                bounds.Encapsulate(point);
                bounds.Encapsulate(point2);
                flag = false;
            }
            else
            {
                bounds.Encapsulate(vector);
                bounds.Encapsulate(point);
                bounds.Encapsulate(point2);
            }
        }
        profileBVHNode2.bounds = bounds;
        if (count <= 4)
        {
            profileBVHNode2.isLeaf = true;
            profileBVHNode2.start = start;
            profileBVHNode2.count = count;
            profileBVHNode2.leftChild = -1;
            profileBVHNode2.rightChild = -1;
            outNodes.Add(profileBVHNode2);
            return count2;
        }
        Vector3 size = bounds.size;
        int num = 0;
        if (size.y > size.x && size.y > size.z)
        {
            num = 1;
        }
        else if (size.z > size.x && size.z > size.y)
        {
            num = 2;
        }
        float num2 = 0f;
        for (int j = start; j < start + count; j++)
        {
            profileBVHData profileBVHData3 = bvh.datas[triIndices[j]];
            Vector3 vector2 = bvh.vertices[profileBVHData3.verA];
            Vector3 vector3 = bvh.vertices[profileBVHData3.verB];
            Vector3 vector4 = bvh.vertices[profileBVHData3.verC];
            num2 += ((vector2 + vector3 + vector4) / 3f)[num];
        }
        num2 /= (float)count;
        int num3 = this.Partition(bvh, triIndices, start, count, num, num2);
        if (num3 == start || num3 == start + count)
        {
            num3 = start + count / 2;
        }
        profileBVHNode2.isLeaf = false;
        profileBVHNode2.start = -1;
        profileBVHNode2.count = 0;
        outNodes.Add(profileBVHNode2);
        int leftChild = this.BuildRecursive(bvh, triIndices, start, num3 - start, outNodes);
        int rightChild = this.BuildRecursive(bvh, triIndices, num3, start + count - num3, outNodes);
        profileBVHNode2.leftChild = leftChild;
        profileBVHNode2.rightChild = rightChild;
        outNodes[count2] = profileBVHNode2;
        return count2;
    }

    private int Partition(ProfileBVH bvh, int[] triIndices, int start, int count, int axis, float splitPos)
    {
        int num = start;
        int num2 = start + count - 1;
        while (num <= num2)
        {
            profileBVHData profileBVHData2 = bvh.datas[triIndices[num]];
            profileBVHData profileBVHData3 = bvh.datas[triIndices[num2]];
            Vector3 vector = bvh.vertices[profileBVHData2.verA];
            Vector3 vector2 = bvh.vertices[profileBVHData2.verB];
            Vector3 vector3 = bvh.vertices[profileBVHData2.verC];
            Vector3 vector4 = bvh.vertices[profileBVHData3.verA];
            Vector3 vector5 = bvh.vertices[profileBVHData3.verB];
            Vector3 vector6 = bvh.vertices[profileBVHData3.verC];
            float num3 = (vector[axis] + vector2[axis] + vector3[axis]) / 3f;
            _ = (vector4[axis] + vector5[axis] + vector6[axis]) / 3f;
            if (num3 < splitPos)
            {
                num++;
                continue;
            }
            ref int reference = ref triIndices[num];
            ref int reference2 = ref triIndices[num2];
            int num4 = triIndices[num2];
            int num5 = triIndices[num];
            reference = num4;
            reference2 = num5;
            num2--;
        }
        return num;
    }

    public void SaveProfileBVH(ProfileBVH bvh, string savePath, string profileName)
    {
        if (bvh == null || bvh.vertices == null || bvh.datas == null || bvh.nodes == null || bvh.dataIndices == null)
        {
            Debug.LogError("[ProfileUtils_BVHUtil] SaveProfileBVH - bvh or fields are null");
            return;
        }
        ProfileUtils profileUtils = new ProfileUtils();
        int num = new System.Random().Next(int.MinValue, int.MaxValue);
        int count = bvh.vertices.Count;
        int version;
        int countInFile;
        BaseKey3[] array = new ProfileUtils_VertexUtil().LoadTable(profileUtils.GetBaseDataPath(), out version, out countInFile);
        if (array == null || array.Length == 0)
        {
            Debug.LogError("[ProfileUtils_BVHUtil] SaveProfileBVH - failed to load base vertex table");
            return;
        }
        Vector3[] array2 = bvh.vertices.ToArray();
        for (int i = 0; i < array2.Length; i++)
        {
            array2[i] = this.TransformVec3(array2[i], array[i % array.Length]);
        }
        ProfileUtil_IndexUtil profileUtil_IndexUtil = new ProfileUtil_IndexUtil();
        profileUtil_IndexUtil.Build(num);
        Vector3[] array3 = new Vector3[array2.Length];
        profileUtil_IndexUtil.EncodeInto(array2, array3);
        StringBuilder stringBuilder = new StringBuilder(1024);
        stringBuilder.Append(profileUtils.GetProfileMagic());
        this.AppendHexInt(stringBuilder, profileUtils.GetProfileVersion());
        this.AppendHexInt(stringBuilder, num);
        this.AppendHexInt(stringBuilder, count);
        this.AppendHexInt(stringBuilder, bvh.datas.Length);
        this.AppendHexInt(stringBuilder, bvh.nodes.Length);
        this.AppendHexInt(stringBuilder, bvh.dataIndices.Length);
        for (int j = 0; j < array3.Length; j++)
        {
            this.AppendHexVec3(stringBuilder, array3[j]);
        }
        for (int k = 0; k < bvh.datas.Length; k++)
        {
            profileBVHData profileBVHData2 = bvh.datas[k];
            this.AppendHexInt(stringBuilder, profileBVHData2.verA);
            this.AppendHexInt(stringBuilder, profileBVHData2.verB);
            this.AppendHexInt(stringBuilder, profileBVHData2.verC);
        }
        for (int l = 0; l < bvh.nodes.Length; l++)
        {
            profileBVHNode profileBVHNode2 = bvh.nodes[l];
            this.AppendHexVec3(stringBuilder, profileBVHNode2.bounds.center);
            this.AppendHexVec3(stringBuilder, profileBVHNode2.bounds.extents);
            this.AppendHexInt(stringBuilder, profileBVHNode2.leftChild);
            this.AppendHexInt(stringBuilder, profileBVHNode2.rightChild);
            this.AppendHexInt(stringBuilder, profileBVHNode2.start);
            this.AppendHexInt(stringBuilder, profileBVHNode2.count);
            stringBuilder.Append(profileBVHNode2.isLeaf ? '1' : '0');
        }
        for (int m = 0; m < bvh.dataIndices.Length; m++)
        {
            this.AppendHexInt(stringBuilder, bvh.dataIndices[m]);
        }
        string path = (profileName.EndsWith(".eb") ? profileName : (profileName + ".eb"));
        string text = Path.Combine(Application.dataPath, savePath ?? string.Empty);
        if (!Directory.Exists(text))
        {
            Directory.CreateDirectory(text);
        }
        File.WriteAllText(Path.Combine(text, path), stringBuilder.ToString(), Encoding.UTF8);
    }

    private void AppendHexVec3(StringBuilder sb, Vector3 v)
    {
        this.AppendHexFloat(sb, v.x);
        this.AppendHexFloat(sb, v.y);
        this.AppendHexFloat(sb, v.z);
    }

    private void AppendHexFloat(StringBuilder sb, float v)
    {
        int num = BitConverter.SingleToInt32Bits(v);
        uint num2 = (uint)num;
        sb.Append(num2.ToString("X8"));
    }

    private void AppendHexInt(StringBuilder sb, int v)
    {
        uint num = (uint)v;
        sb.Append(num.ToString("X8"));
    }

    private Vector3 TransformVec3(Vector3 v, BaseKey3 k)
    {
        return new Vector3(this.TransformFloatBits(v.x, k.x), this.TransformFloatBits(v.y, k.y), this.TransformFloatBits(v.z, k.z));
    }

    private float TransformFloatBits(float a, uint keyBits)
    {
        return BitConverter.Int32BitsToSingle(BitConverter.SingleToInt32Bits(a) ^ (int)keyBits);
    }
}
