/** * @file llrect.h * @brief A rectangle in GL coordinates, with bottom,left = 0,0 * * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/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 = ((F32)clip_x / (F32)delta_x); F32 ratio_y = ((F32)clip_y / (F32)delta_y); 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