#ifndef _gpuCacheFrustum_h_
#define _gpuCacheFrustum_h_
#include <maya/MMatrix.h>
#include <maya/MBoundingBox.h>
#include <cassert>
namespace GPUCache {
    
class Frustum
{
public:
    
    
    
    enum ClippingResult {
        kIntersectsLeft     = (1),
        kIntersectsRight    = (1 << 1),
        kIntersectsBottom   = (1 << 2),
        kIntersectsTop      = (1 << 3),
        kIntersectsNear     = (1 << 4),
        kIntersectsFar      = (1 << 5),
        kIntersectsMask     = kIntersectsLeft | kIntersectsRight |
                              kIntersectsBottom | kIntersectsTop |
                              kIntersectsNear | kIntersectsFar,
        kOutside            = (1 << 6),
        kInside             = (1 << 7),
        kIntersects         = kIntersectsMask,
        kUnknown            = kIntersectsMask,
    };
        kDirectX,
    };
    
    
        const ClippingResult& parentResult = kUnknown) const
    {
        
        assert(!(parentResult & (kOutside | kInside)));
            
        int result    = 0;
        int intersect = 1;
        for (int i=kFirstPlane; i<=kLastPlane; ++i,intersect=intersect<<1) {
            
            
            
            if (parentResult & intersect) {
                
                
                ClippingResult res = planes[i].test(pmin, pmax);
                
                if (res == kOutside) {
                    return kOutside;
                }
                
                if (res == kIntersects) {
                    result = result | intersect;
                }
            }
        }
        
        if (!(result & kIntersectsMask)) {
            return kInside;
        }
        
        return (ClippingResult)result;
    }        
        
private:
        
    
    
    enum PlaneId {
        kLeft,
        kRight,
        kBottom,
        kTop,
        kNear,
        kFar,
        kFirstPlane = kLeft,
        kLastPlane = kFar
    };
    
    
    class Plane 
    {
    public:
            
        
        
        
        
        
        
        
        
        
        
        
        {
            d = -(n.
x*p1.x + n.
y*p1.y + n.
z*p1.z);
            if (distance(opp) < 0.0f) {
                a = -a; b = -b; c = -c; d = -d;
            }
        }
        double distance(double x, double y, double z) const
        {
            return a*x + b*y + c*z + d;
        }
            
        double distance(
const MPoint& p)
 const 
        {
            return distance(p.
x, p.
y, p.
z);
 
        }
        ClippingResult test(
const MPoint& pmin,
        {
            const bool sa = a > 0.0;
            const bool sb = b > 0.0;
            const bool sc = c > 0.0;
            
            if (distance(sa ? pmax.
x : pmin.
x,
 
                         sc ? pmax.
z : pmin.
z) < 0.0)
                return kOutside;
            
            if (distance(sa ? pmin.
x : pmax.
x,
 
                         sc ? pmin.
z : pmax.
z) > 0.0)
                return kInside;
            return kIntersects;
        }
        void print(const char* name,
                    
    private:
            
        
        
        double a, b, c, d;
    };
    
    
    
    Plane planes[6];
};
    
} 
#endif