#include "BsRect2I.h" #include "BsVector2I.h" #include "BsMatrix4.h" #include "BsMath.h" namespace BansheeEngine { const Rect2I Rect2I::EMPTY = Rect2I(); Rect2I::Rect2I() :x(0), y(0), width(0), height(0) { } Rect2I::Rect2I(int _x, int _y, int _width, int _height) :x(_x), y(_y), width(_width), height(_height) { } bool Rect2I::contains(const Vector2I& point) const { if(point.x >= x && point.x < (x + width)) { if(point.y >= y && point.y < (y + height)) return true; } return false; } bool Rect2I::overlaps(const Rect2I& other) const { INT32 otherRight = other.x + other.width; INT32 myRight = x + width; INT32 otherBottom = other.y + other.height; INT32 myBottom = y + height; if(x < otherRight && myRight > other.x && y < otherBottom && myBottom > other.y) return true; return false; } void Rect2I::encapsulate(const Rect2I& other) { int myRight = x + width; int myBottom = y + height; int otherRight = other.x + other.width; int otherBottom = other.y + other.height; if(other.x < x) x = other.x; if(other.y < y) y = other.y; if(otherRight > myRight) width = otherRight - x; else width = myRight - x; if(otherBottom > myBottom) height = otherBottom - y; else height = myBottom - y; } void Rect2I::clip(const Rect2I& clipRect) { int newLeft = std::max(x, clipRect.x); int newTop = std::max(y, clipRect.y); int newRight = std::min(x + width, clipRect.x + clipRect.width); int newBottom = std::min(y + height, clipRect.y + clipRect.height); x = std::min(newLeft, newRight); y = std::min(newTop, newBottom); width = std::max(0, newRight - newLeft); height = std::max(0, newBottom - newTop); } void Rect2I::cut(const Rect2I& cutRect, Vector& pieces) { UINT32 initialPieces = (UINT32)pieces.size(); // Cut horizontal if (cutRect.x > x && cutRect.x < (x + width)) { Rect2I leftPiece; leftPiece.x = x; leftPiece.width = cutRect.x - x; leftPiece.y = y; leftPiece.height = height; pieces.push_back(leftPiece); } if ((cutRect.x + cutRect.width) > x && (cutRect.x + cutRect.width) < (x + width)) { Rect2I rightPiece; rightPiece.x = cutRect.x + cutRect.width; rightPiece.width = (x + width) - (cutRect.x + cutRect.width); rightPiece.y = y; rightPiece.height = height; pieces.push_back(rightPiece); } // Cut vertical INT32 cutLeft = std::min(std::max(x, cutRect.x), x + width); INT32 cutRight = std::max(std::min(x + width, cutRect.x + cutRect.width), x); if (cutLeft != cutRight) { if (cutRect.y > y && cutRect.y < (y + height)) { Rect2I topPiece; topPiece.y = y; topPiece.height = cutRect.y - y; topPiece.x = cutLeft; topPiece.width = cutRight - cutLeft; pieces.push_back(topPiece); } if ((cutRect.y + cutRect.height) > y && (cutRect.y + cutRect.height) < (y + height)) { Rect2I bottomPiece; bottomPiece.y = cutRect.y + cutRect.height; bottomPiece.height = (y + height) - (cutRect.y + cutRect.height); bottomPiece.x = cutLeft; bottomPiece.width = cutRight - cutLeft; pieces.push_back(bottomPiece); } } // No cut if (initialPieces == (UINT32)pieces.size()) { if (cutRect.x <= x && (cutRect.x + cutRect.width) >= (x + width) && cutRect.y <= y && (cutRect.y + cutRect.height) >= (y + height)) { // Cut rectangle completely encompasses this one } else pieces.push_back(*this); // Cut rectangle doesn't even touch this one } } void Rect2I::cut(const Vector& cutRects, Vector& pieces) { Vector tempPieces[2]; UINT32 bufferIdx = 0; tempPieces[0].push_back(*this); for (auto& cutRect : cutRects) { UINT32 currentBufferIdx = bufferIdx; bufferIdx = (bufferIdx + 1) % 2; tempPieces[bufferIdx].clear(); for (auto& rect : tempPieces[currentBufferIdx]) rect.cut(cutRect, tempPieces[bufferIdx]); } pieces = tempPieces[bufferIdx]; } void Rect2I::transform(const Matrix4& matrix) { Vector4 verts[4]; verts[0] = Vector4((float)x, (float)y, 0.0f, 1.0f); verts[1] = Vector4((float)x + width, (float)y, 0.0f, 1.0f); verts[2] = Vector4((float)x, (float)y + height, 0.0f, 1.0f); verts[3] = Vector4((float)x + width, (float)y + height, 0.0f, 1.0f); for(UINT32 i = 0; i < 4; i++) verts[i] = matrix.multiply(verts[i]); float minX = std::numeric_limits::max(); float maxX = std::numeric_limits::min(); float minY = std::numeric_limits::max(); float maxY = std::numeric_limits::min(); for(UINT32 i = 0; i < 4; i++) { if(verts[i].x < minX) minX = verts[i].x; if(verts[i].y < minY) minY = verts[i].y; if(verts[i].x > maxX) maxX = verts[i].x; if(verts[i].y > maxY) maxY = verts[i].y; } x = Math::floorToInt(minX); y = Math::floorToInt(minY); width = Math::ceilToInt(maxX) - x; height = Math::ceilToInt(maxY) - y; } }