BsRect2I.cpp 5.3 KB

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