1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Math/BsRect2I.h"
4#include "Math/BsVector2I.h"
5#include "Math/BsMatrix4.h"
6#include "Math/BsMath.h"
7
8namespace bs
9{
10 const Rect2I Rect2I::EMPTY;
11
12 bool Rect2I::contains(const Vector2I& point) const
13 {
14 if(point.x >= x && point.x < (x + (INT32)width))
15 {
16 if(point.y >= y && point.y < (y + (INT32)height))
17 return true;
18 }
19
20 return false;
21 }
22
23 bool Rect2I::overlaps(const Rect2I& other) const
24 {
25 INT32 otherRight = other.x + (INT32)other.width;
26 INT32 myRight = x + (INT32)width;
27
28 INT32 otherBottom = other.y + (INT32)other.height;
29 INT32 myBottom = y + (INT32)height;
30
31 if(x < otherRight && myRight > other.x &&
32 y < otherBottom && myBottom > other.y)
33 return true;
34
35 return false;
36 }
37
38 void Rect2I::encapsulate(const Rect2I& other)
39 {
40 int myRight = x + (INT32)width;
41 int myBottom = y + (INT32)height;
42 int otherRight = other.x + (INT32)other.width;
43 int otherBottom = other.y + (INT32)other.height;
44
45 if(other.x < x)
46 x = other.x;
47
48 if(other.y < y)
49 y = other.y;
50
51 if(otherRight > myRight)
52 width = otherRight - x;
53 else
54 width = myRight - x;
55
56 if(otherBottom > myBottom)
57 height = otherBottom - y;
58 else
59 height = myBottom - y;
60 }
61
62 void Rect2I::clip(const Rect2I& clipRect)
63 {
64 int newLeft = std::max(x, clipRect.x);
65 int newTop = std::max(y, clipRect.y);
66
67 int newRight = std::min(x + (INT32)width, clipRect.x + (INT32)clipRect.width);
68 int newBottom = std::min(y + (INT32)height, clipRect.y + (INT32)clipRect.height);
69
70 x = std::min(newLeft, newRight);
71 y = std::min(newTop, newBottom);
72 width = std::max(0, newRight - newLeft);
73 height = std::max(0, newBottom - newTop);
74 }
75
76 void Rect2I::cut(const Rect2I& cutRect, Vector<Rect2I>& pieces)
77 {
78 UINT32 initialPieces = (UINT32)pieces.size();
79
80 // Cut horizontal
81 if (cutRect.x > x && cutRect.x < (x + (INT32)width))
82 {
83 Rect2I leftPiece;
84 leftPiece.x = x;
85 leftPiece.width = cutRect.x - x;
86 leftPiece.y = y;
87 leftPiece.height = height;
88
89 pieces.push_back(leftPiece);
90 }
91
92 if ((cutRect.x + (INT32)cutRect.width) > x && (cutRect.x + (INT32)cutRect.width) < (x + (INT32)width))
93 {
94 Rect2I rightPiece;
95 rightPiece.x = cutRect.x + cutRect.width;
96 rightPiece.width = (x + width) - (cutRect.x + cutRect.width);
97 rightPiece.y = y;
98 rightPiece.height = height;
99
100 pieces.push_back(rightPiece);
101 }
102
103 // Cut vertical
104 INT32 cutLeft = std::min(std::max(x, cutRect.x), x + (INT32)width);
105 INT32 cutRight = std::max(std::min(x + (INT32)width, cutRect.x + (INT32)cutRect.width), x);
106
107 if (cutLeft != cutRight)
108 {
109 if (cutRect.y > y && cutRect.y < (y + (INT32)height))
110 {
111 Rect2I topPiece;
112 topPiece.y = y;
113 topPiece.height = cutRect.y - y;
114 topPiece.x = cutLeft;
115 topPiece.width = cutRight - cutLeft;
116
117 pieces.push_back(topPiece);
118 }
119
120 if ((cutRect.y + (INT32)cutRect.height) > y && (cutRect.y + (INT32)cutRect.height) < (y + (INT32)height))
121 {
122 Rect2I bottomPiece;
123 bottomPiece.y = cutRect.y + cutRect.height;
124 bottomPiece.height = (y + height) - (cutRect.y + cutRect.height);
125 bottomPiece.x = cutLeft;
126 bottomPiece.width = cutRight - cutLeft;
127
128 pieces.push_back(bottomPiece);
129 }
130 }
131
132 // No cut
133 if (initialPieces == (UINT32)pieces.size())
134 {
135 if (cutRect.x <= x && (cutRect.x + (INT32)cutRect.width) >= (x + (INT32)width) &&
136 cutRect.y <= y && (cutRect.y + (INT32)cutRect.height) >= (y + (INT32)height))
137 {
138 // Cut rectangle completely encompasses this one
139 }
140 else
141 pieces.push_back(*this); // Cut rectangle doesn't even touch this one
142 }
143 }
144
145 void Rect2I::cut(const Vector<Rect2I>& cutRects, Vector<Rect2I>& pieces)
146 {
147 Vector<Rect2I> tempPieces[2];
148 UINT32 bufferIdx = 0;
149
150 tempPieces[0].push_back(*this);
151
152 for (auto& cutRect : cutRects)
153 {
154 UINT32 currentBufferIdx = bufferIdx;
155
156 bufferIdx = (bufferIdx + 1) % 2;
157 tempPieces[bufferIdx].clear();
158
159 for (auto& rect : tempPieces[currentBufferIdx])
160 rect.cut(cutRect, tempPieces[bufferIdx]);
161 }
162
163 pieces = tempPieces[bufferIdx];
164 }
165
166 void Rect2I::transform(const Matrix4& matrix)
167 {
168 Vector4 verts[4];
169 verts[0] = Vector4((float)x, (float)y, 0.0f, 1.0f);
170 verts[1] = Vector4((float)x + width, (float)y, 0.0f, 1.0f);
171 verts[2] = Vector4((float)x, (float)y + height, 0.0f, 1.0f);
172 verts[3] = Vector4((float)x + width, (float)y + height, 0.0f, 1.0f);
173
174 for(UINT32 i = 0; i < 4; i++)
175 verts[i] = matrix.multiply(verts[i]);
176
177 float minX = std::numeric_limits<float>::max();
178 float maxX = std::numeric_limits<float>::min();
179 float minY = std::numeric_limits<float>::max();
180 float maxY = std::numeric_limits<float>::min();
181
182 for(UINT32 i = 0; i < 4; i++)
183 {
184 if(verts[i].x < minX)
185 minX = verts[i].x;
186
187 if(verts[i].y < minY)
188 minY = verts[i].y;
189
190 if(verts[i].x > maxX)
191 maxX = verts[i].x;
192
193 if(verts[i].y > maxY)
194 maxY = verts[i].y;
195 }
196
197 x = Math::floorToInt(minX);
198 y = Math::floorToInt(minY);
199 width = (UINT32)Math::ceilToInt(maxX) - x;
200 height = (UINT32)Math::ceilToInt(maxY) - y;
201 }
202}
203