/*
 *Copyright(C) 2020 by  Chief All rights reserved.
 *Unity版本：2020.2.20b8
 *作者:程一峰  
 *创建日期: 2022-04-29 
 *模块说明：
 *版本: 0.9
*/

using Unity.Collections;
using Unity.Mathematics;

namespace Aster
{
    /// <summary>
    /// 相机包围盒裁剪；
    /// </summary>
    public struct FrustumPlanes
    {
        public enum InsideResult
        {
            Out,//外侧
            In,//包含在内（指整个包围盒都在相机视锥体内）
            Partial//部分包含
        };

        internal NativeArray<float4> mPlanes;

        public FrustumPlanes(NativeArray<float4> planes_)
        {
            mPlanes = planes_;
        }

        /// <summary>
        /// 球状剔除
        /// </summary>
        /// <param name="center">球中心</param>
        /// <param name="radius">半径</param>
        public InsideResult Inside(float3 center, float radius)
        {
            int length = mPlanes.Length;
            bool all_in = true;
            for (int i = 0; i < length; i++)
            {
                float4 plane = mPlanes[i];
                float3 normal = plane.xyz;
                var distance = math.dot(normal, center) + plane.w;
                if (distance < -radius)
                    return InsideResult.Out;

                all_in = all_in && (distance > radius);
            }

            return all_in ? InsideResult.In : InsideResult.Partial;
        }

        /// <summary>
        /// 方形包围盒剔除
        /// </summary>
        /// <param name="center">盒子中心</param>
        /// <param name="extents">外沿尺寸（size的一半）</param>
        public InsideResult Inside(float3 center, float3 extents)
        {
            int length = mPlanes.Length;
            bool all_in = true;
            for (int i = 0; i < length; i++)
            {
                float4 plane = mPlanes[i];
                float3 normal = plane.xyz;
                float dist = math.dot(normal, center) + plane.w;
                float radius = math.dot(extents, math.abs(normal));
                if (dist <= -radius)
                    return InsideResult.Out;

                all_in &= dist > radius;
            }

            return all_in ? InsideResult.In : InsideResult.Partial;
        }

    }
}