297 lines
7.0 KiB
C++
297 lines
7.0 KiB
C++
/**
|
|
* @file llrect.h
|
|
* @brief A rectangle in GL coordinates, with bottom,left = 0,0
|
|
*
|
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
|
|
#ifndef LL_LLRECT_H
|
|
#define LL_LLRECT_H
|
|
|
|
#include <iostream>
|
|
#include "llmath.h"
|
|
#include "llsd.h"
|
|
|
|
// Top > Bottom due to GL coords
|
|
template <class Type> class LLRectBase
|
|
{
|
|
public:
|
|
typedef Type tCoordType;
|
|
Type mLeft;
|
|
Type mTop;
|
|
Type mRight;
|
|
Type mBottom;
|
|
|
|
// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
|
|
Type getWidth() const { return mRight - mLeft; }
|
|
Type getHeight() const { return mTop - mBottom; }
|
|
Type getCenterX() const { return (mLeft + mRight) / 2; }
|
|
Type getCenterY() const { return (mTop + mBottom) / 2; }
|
|
|
|
LLRectBase(): mLeft(0), mTop(0), mRight(0), mBottom(0)
|
|
{}
|
|
|
|
LLRectBase(const LLRectBase &r):
|
|
mLeft(r.mLeft), mTop(r.mTop), mRight(r.mRight), mBottom(r.mBottom)
|
|
{}
|
|
|
|
LLRectBase(Type left, Type top, Type right, Type bottom):
|
|
mLeft(left), mTop(top), mRight(right), mBottom(bottom)
|
|
{}
|
|
|
|
/*explicit */LLRectBase(const LLSD& sd)
|
|
{
|
|
setValue(sd);
|
|
}
|
|
|
|
void setValue(const LLSD& sd)
|
|
{
|
|
mLeft = (Type)sd[0].asInteger();
|
|
mTop = (Type)sd[1].asInteger();
|
|
mRight = (Type)sd[2].asInteger();
|
|
mBottom = (Type)sd[3].asInteger();
|
|
}
|
|
|
|
LLSD getValue() const
|
|
{
|
|
LLSD ret;
|
|
ret[0] = mLeft;
|
|
ret[1] = mTop;
|
|
ret[2] = mRight;
|
|
ret[3] = mBottom;
|
|
return ret;
|
|
}
|
|
|
|
// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
|
|
BOOL pointInRect(const Type x, const Type y) const
|
|
{
|
|
return mLeft <= x && x < mRight &&
|
|
mBottom <= y && y < mTop;
|
|
}
|
|
|
|
//// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
|
|
BOOL localPointInRect(const Type x, const Type y) const
|
|
{
|
|
return 0 <= x && x < getWidth() &&
|
|
0 <= y && y < getHeight();
|
|
}
|
|
|
|
void clampPointToRect(Type& x, Type& y)
|
|
{
|
|
x = llclamp(x, mLeft, mRight);
|
|
y = llclamp(y, mBottom, mTop);
|
|
}
|
|
|
|
void clipPointToRect(const Type start_x, const Type start_y, Type& end_x, Type& end_y)
|
|
{
|
|
if (!pointInRect(start_x, start_y))
|
|
{
|
|
return;
|
|
}
|
|
Type clip_x = 0;
|
|
Type clip_y = 0;
|
|
Type delta_x = end_x - start_x;
|
|
Type delta_y = end_y - start_y;
|
|
if (end_x > mRight) clip_x = end_x - mRight;
|
|
if (end_x < mLeft) clip_x = end_x - mLeft;
|
|
if (end_y > mTop) clip_y = end_y - mTop;
|
|
if (end_y < mBottom) clip_y = end_y - mBottom;
|
|
// clip_? and delta_? should have same sign, since starting point is in rect
|
|
// so ratios will be positive
|
|
F32 ratio_x = delta_x ? ((F32)clip_x / (F32)delta_x) : 0.f;
|
|
F32 ratio_y = delta_y ? ((F32)clip_y / (F32)delta_y) : 0.f;
|
|
if (ratio_x > ratio_y)
|
|
{
|
|
// clip along x direction
|
|
end_x -= (Type)(clip_x);
|
|
end_y -= (Type)(delta_y * ratio_x);
|
|
}
|
|
else
|
|
{
|
|
// clip along y direction
|
|
end_x -= (Type)(delta_x * ratio_y);
|
|
end_y -= (Type)clip_y;
|
|
}
|
|
}
|
|
|
|
// Note: Does NOT follow GL_QUAD conventions: the top and right edges ARE considered part of the rect
|
|
// returns TRUE if any part of rect is is inside this LLRect
|
|
BOOL overlaps(const LLRectBase& rect) const
|
|
{
|
|
return !(mLeft > rect.mRight
|
|
|| mRight < rect.mLeft
|
|
|| mBottom > rect.mTop
|
|
|| mTop < rect.mBottom);
|
|
}
|
|
|
|
BOOL contains(const LLRectBase& rect) const
|
|
{
|
|
return mLeft <= rect.mLeft
|
|
&& mRight >= rect.mRight
|
|
&& mBottom <= rect.mBottom
|
|
&& mTop >= rect.mTop;
|
|
}
|
|
|
|
LLRectBase& set(Type left, Type top, Type right, Type bottom)
|
|
{
|
|
mLeft = left;
|
|
mTop = top;
|
|
mRight = right;
|
|
mBottom = bottom;
|
|
return *this;
|
|
}
|
|
|
|
// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
|
|
LLRectBase& setOriginAndSize( Type left, Type bottom, Type width, Type height)
|
|
{
|
|
mLeft = left;
|
|
mTop = bottom + height;
|
|
mRight = left + width;
|
|
mBottom = bottom;
|
|
return *this;
|
|
}
|
|
|
|
// Note: follows GL_QUAD conventions: the top and right edges are not considered part of the rect
|
|
LLRectBase& setLeftTopAndSize( Type left, Type top, Type width, Type height)
|
|
{
|
|
mLeft = left;
|
|
mTop = top;
|
|
mRight = left + width;
|
|
mBottom = top - height;
|
|
return *this;
|
|
}
|
|
|
|
LLRectBase& setCenterAndSize(Type x, Type y, Type width, Type height)
|
|
{
|
|
// width and height could be odd, so favor top, right with extra pixel
|
|
mLeft = x - width/2;
|
|
mBottom = y - height/2;
|
|
mTop = mBottom + height;
|
|
mRight = mLeft + width;
|
|
return *this;
|
|
}
|
|
|
|
|
|
LLRectBase& translate(Type horiz, Type vertical)
|
|
{
|
|
mLeft += horiz;
|
|
mRight += horiz;
|
|
mTop += vertical;
|
|
mBottom += vertical;
|
|
return *this;
|
|
}
|
|
|
|
LLRectBase& stretch( Type dx, Type dy)
|
|
{
|
|
mLeft -= dx;
|
|
mRight += dx;
|
|
mTop += dy;
|
|
mBottom -= dy;
|
|
return makeValid();
|
|
}
|
|
|
|
LLRectBase& stretch( Type delta )
|
|
{
|
|
stretch(delta, delta);
|
|
return *this;
|
|
}
|
|
|
|
LLRectBase& makeValid()
|
|
{
|
|
mLeft = llmin(mLeft, mRight);
|
|
mBottom = llmin(mBottom, mTop);
|
|
return *this;
|
|
}
|
|
|
|
bool isValid() const
|
|
{
|
|
return mLeft <= mRight && mBottom <= mTop;
|
|
}
|
|
|
|
bool isEmpty() const
|
|
{
|
|
return mLeft == mRight || mBottom == mTop;
|
|
}
|
|
|
|
bool notEmpty() const
|
|
{
|
|
return !isEmpty();
|
|
}
|
|
|
|
void unionWith(const LLRectBase &other)
|
|
{
|
|
mLeft = llmin(mLeft, other.mLeft);
|
|
mRight = llmax(mRight, other.mRight);
|
|
mBottom = llmin(mBottom, other.mBottom);
|
|
mTop = llmax(mTop, other.mTop);
|
|
}
|
|
|
|
void intersectWith(const LLRectBase &other)
|
|
{
|
|
mLeft = llmax(mLeft, other.mLeft);
|
|
mRight = llmin(mRight, other.mRight);
|
|
mBottom = llmax(mBottom, other.mBottom);
|
|
mTop = llmin(mTop, other.mTop);
|
|
if (mLeft > mRight)
|
|
{
|
|
mLeft = mRight;
|
|
}
|
|
if (mBottom > mTop)
|
|
{
|
|
mBottom = mTop;
|
|
}
|
|
}
|
|
|
|
friend std::ostream &operator<<(std::ostream &s, const LLRectBase &rect)
|
|
{
|
|
s << "{ L " << rect.mLeft << " B " << rect.mBottom
|
|
<< " W " << rect.getWidth() << " H " << rect.getHeight() << " }";
|
|
return s;
|
|
}
|
|
|
|
bool operator==(const LLRectBase &b) const
|
|
{
|
|
return ((mLeft == b.mLeft) &&
|
|
(mTop == b.mTop) &&
|
|
(mRight == b.mRight) &&
|
|
(mBottom == b.mBottom));
|
|
}
|
|
|
|
bool operator!=(const LLRectBase &b) const
|
|
{
|
|
return ((mLeft != b.mLeft) ||
|
|
(mTop != b.mTop) ||
|
|
(mRight != b.mRight) ||
|
|
(mBottom != b.mBottom));
|
|
}
|
|
|
|
static LLRectBase<Type> null;
|
|
};
|
|
|
|
template <class Type> LLRectBase<Type> LLRectBase<Type>::null(0,0,0,0);
|
|
|
|
typedef LLRectBase<S32> LLRect;
|
|
typedef LLRectBase<F32> LLRectf;
|
|
|
|
#endif
|