struct HS_RECT_NAME {
    HS_RECT_TYPE        fLeft, fTop, fRight, fBottom;

    HS_RECT_TYPE        Width() const { return fRight - fLeft; }
    HS_RECT_TYPE        Height() const { return fBottom - fTop; }
    hsBool          IsEmpty() const { return fLeft >= fRight || fTop >= fBottom; }

    void                SetEmpty() { fLeft = fTop = fRight = fBottom = 0; }
    HS_RECT_NAME*   Set(HS_RECT_TYPE left, HS_RECT_TYPE top, HS_RECT_TYPE right, HS_RECT_TYPE bottom)
                {
                    fLeft = left; fTop = top; fRight = right; fBottom = bottom;
                    return this;
                }
    HS_RECT_NAME*   Set(const HS_RECT_POINT* p1, const HS_RECT_POINT* p2)
                {
                    if (p1->fX < p2->fX)
                    {   fLeft       = p1->fX;
                        fRight  = p2->fX;
                    } else
                    {   fLeft       = p2->fX;
                        fRight  = p1->fX;
                    }
                    
                    if (p1->fY < p2->fY)
                    {   fTop        = p1->fY;
                        fBottom = p2->fY;
                    } else
                    {   fTop        = p2->fY;
                        fBottom = p1->fY;
                    }
                    return this;
                }
    HS_RECT_NAME*   Set(UInt32 count, const HS_RECT_POINT pts[])
                {
                    if (count > 0)
                    {   fLeft = fRight = pts[0].fX;
                        fTop = fBottom = pts[0].fY;
                        (void)this->Union(count - 1, &pts[1]);
                    }
                    return this;
                }

    hsBool      Contains(HS_RECT_TYPE x, HS_RECT_TYPE y) const
                {
                    return x >= fLeft && x < fRight && y >= fTop && y < fBottom;
                }
    hsBool      Contains(const HS_RECT_POINT* p) const
                {
                    return this->Contains(p->fX, p->fY);
                }
    hsBool      Contains(const HS_RECT_NAME* r) const
                {
                    return fLeft <= r->fLeft && fTop <= r->fTop && fRight >= r->fRight && fBottom >= r->fBottom;
                }
    hsBool      Contains(HS_RECT_TYPE left, HS_RECT_TYPE top, HS_RECT_TYPE right, HS_RECT_TYPE bottom) const
                {
                    return fLeft <= left && fTop <= top && fRight >= right && fBottom >= bottom;
                }
    HS_RECT_NAME*   Offset(HS_RECT_TYPE dx, HS_RECT_TYPE dy)
                {
                    fLeft += dx; fTop += dy; fRight += dx; fBottom += dy;
                    return this;
                }
    HS_RECT_NAME*   MoveTo(HS_RECT_TYPE x, HS_RECT_TYPE y)
                {
                    this->fRight += x - this->fLeft;
                    this->fBottom += y - this->fTop;
                    this->fLeft = x;
                    this->fTop = y;
                    return this;
                }
    HS_RECT_NAME*   Inset(HS_RECT_TYPE dx, HS_RECT_TYPE dy)
                {
                    fLeft += dx; fRight -= dx;
                    fTop += dy; fBottom -= dy;
                    return this;
                }

    HS_RECT_NAME*   UnionX(HS_RECT_TYPE x)
                {
                    if (x < fLeft) fLeft = x; else
                    if (x > fRight) fRight = x;
                    return this;
                }
    HS_RECT_NAME*   UnionY(HS_RECT_TYPE y)
                {
                    if (y < fTop) fTop = y; else
                    if (y > fBottom) fBottom = y;
                    return this;
                }
    HS_RECT_NAME*   Union(const HS_RECT_NAME* r)
                {
                    if (r->fLeft < fLeft)       fLeft = r->fLeft;
                    if (r->fTop < fTop)     fTop = r->fTop;
                    if (r->fRight > fRight) fRight = r->fRight;
                    if (r->fBottom > fBottom)   fBottom = r->fBottom;
                    return this;
                }
    HS_RECT_NAME*   Union(const HS_RECT_POINT* p)
                {
                    if (p->fX < fLeft)  fLeft = p->fX;
                    if (p->fX > fRight) fRight = p->fX;
                    if (p->fY < fTop)   fTop = p->fY;
                    if (p->fY> fBottom) fBottom = p->fY;
                    return this;    
                }
    HS_RECT_NAME*   Union(UInt32 count, const HS_RECT_POINT p[])
                {
                    HS_RECT_TYPE    left = this->fLeft;
                    HS_RECT_TYPE    top = this->fTop;
                    HS_RECT_TYPE    right = this->fRight;
                    HS_RECT_TYPE    bottom = this->fBottom;
                    
                    for (; count > 0; ++p, --count)
                    {   HS_RECT_TYPE    value = p->fX;
                        if (value < left)           left = value;
                        else if (value > right) right = value;
                        
                        value = p->fY;
                        if (value < top)            top = value;
                        else if (value > bottom)    bottom = value;
                    }
                    return this->Set(left, top, right, bottom);
                }

#if 0 // Havok reeks
    friend int      operator==(const HS_RECT_NAME& a, const HS_RECT_NAME& b)
                {
                    return  a.fLeft == b.fLeft && a.fTop == b.fTop &&
                            a.fRight == b.fRight && a.fBottom == b.fBottom;
                }
    friend int      operator!=(const HS_RECT_NAME& a, const HS_RECT_NAME& b)
                {
                    return !(a == b);
                }
#else // Havok reeks
    int     operator==(const HS_RECT_NAME& aa) const
                {
                    return  aa.fLeft == fLeft && aa.fTop == fTop &&
                            aa.fRight == fRight && aa.fBottom == fBottom;
                }
    int     operator!=(const HS_RECT_NAME& aa) const
                {
                    return !(aa == *this);
                }
#endif // Havok reeks

                // Intersect Test
    friend int      operator&&(const HS_RECT_NAME& a, const HS_RECT_NAME& b)
                {
                    return  a.fLeft < b.fRight && a.fRight > b.fLeft &&
                            a.fTop < b.fBottom && a.fBottom > b.fTop;
                }

    hsBool      Intersect(const HS_RECT_NAME* r)
                {
                    return this->Intersect(r->fLeft, r->fTop, r->fRight, r->fBottom);
                }
    hsBool      Intersect(HS_RECT_TYPE left, HS_RECT_TYPE top, HS_RECT_TYPE right, HS_RECT_TYPE bottom)
                {
                    if (left < fRight && top < fBottom && fLeft < right && fTop < bottom)
                    {   if (left > fLeft)           fLeft = left;
                        if (top > fTop)         fTop = top;
                        if (right < fRight)     fRight = right;
                        if (bottom < fBottom)   fBottom = bottom;
                        return true;
                    }
                    return false;
                }
    hsBool      Intersect(const HS_RECT_NAME* a, const HS_RECT_NAME* b)
                {
                    if (a->fLeft < b->fRight && a->fTop < b->fBottom && b->fLeft < a->fRight && b->fTop < a->fBottom)
                    {   *this = *b;
                        if (a->fLeft > fLeft)       fLeft = a->fLeft;
                        if (a->fTop > fTop)     fTop = a->fTop;
                        if (a->fRight < fRight) fRight = a->fRight;
                        if (a->fBottom < fBottom)   fBottom = a->fBottom;
                        return true;
                    }
                    return false;   // "this" is not changed
                }

    HS_RECT_POINT*  ToQuad(HS_RECT_POINT quad[4]) const
                {
                    quad[0].fX = fLeft; quad[0].fY = fTop;
                    quad[1].fX = fRight;    quad[1].fY = fTop;
                    quad[2].fX = fRight;    quad[2].fY = fBottom;
                    quad[3].fX = fLeft; quad[3].fY = fBottom;
                    return quad;
                }

    hsBool      CornerTest(const HS_RECT_NAME* area,
                        HS_RECT_POINT* hitPt = nil, HS_RECT_POINT* oppositePt = nil) const
                {
                    if (area->Contains(fLeft, fTop))
                    {   if (hitPt)  hitPt->Set(fLeft, fTop);
                        if (oppositePt) oppositePt->Set(fRight, fBottom);
                        return true;
                    }
                    if (area->Contains(fLeft, fBottom))
                    {   if (hitPt)  hitPt->Set(fLeft, fBottom);
                        if (oppositePt) oppositePt->Set(fRight, fTop);
                        return true;
                    }
                    if (area->Contains(fRight, fTop))
                    {   if (hitPt)  hitPt->Set(fRight, fTop);
                        if (oppositePt) oppositePt->Set(fLeft, fBottom);
                        return true;
                    }
                    if (area->Contains(fRight, fBottom))
                    {   if (hitPt)  hitPt->Set(fRight, fBottom);
                        if (oppositePt) oppositePt->Set(fLeft, fTop);
                        return true;
                    }
                    return false;
                }
    hsBool      CornerTest(HS_RECT_POINT* pt, HS_RECT_TYPE tolerance,
                        HS_RECT_POINT* hitPt = nil, HS_RECT_POINT* oppositePt = nil) const
                {
                    HS_RECT_NAME area = {   pt->fX - tolerance, pt->fY - tolerance,
                                        pt->fX + tolerance, pt->fY + tolerance };

                    return this->CornerTest(&area, hitPt, oppositePt);
                }

#if !(HS_RECT_EXTEND)
};
#endif

#undef HS_RECT_NAME
#undef HS_RECT_POINT
#undef HS_RECT_TYPE
#undef HS_RECT_EXTEND