FastEngine 0.9.4
A multiplayer oriented 2D engine made with Vulkan.
Loading...
Searching...
No Matches
C_rect.inl
1/*
2 * Copyright 2025 Guillaume Guillet
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17namespace fge
18{
19
20template<class T>
21Rect<T>::Rect() :
22 _x(0),
23 _y(0),
24 _width(0),
25 _height(0)
26{}
27
28template<class T>
29Rect<T>::Rect(Vector2<T> const& position, Vector2<T> const& size) :
30 _x(position.x),
31 _y(position.y),
32 _width(size.x),
33 _height(size.y)
34{}
35
36template<class T>
37template<class U>
38Rect<T>::Rect(Rect<U> const& rectangle) :
39 _x(static_cast<T>(rectangle._x)),
40 _y(static_cast<T>(rectangle._y)),
41 _width(static_cast<T>(rectangle._width)),
42 _height(static_cast<T>(rectangle._height))
43{}
44
45template<class T>
46bool Rect<T>::operator==(Rect<T> const& right) const
47{
48 return (this->_x == right._x) && (this->_width == right._width) && (this->_y == right._y) &&
49 (this->_height == right._height);
50}
51
52template<class T>
53bool Rect<T>::operator!=(Rect<T> const& right) const
54{
55 return !this->operator==(right);
56}
57
58template<class T>
59bool Rect<T>::contains(Vector2<T> const& point) const
60{
61 // Rectangles with negative dimensions are allowed, so we must handle them correctly
62 T const farX = static_cast<T>(this->_x + this->_width);
63 T const farY = static_cast<T>(this->_y + this->_height);
64
65 // Compute the real min and max of the rectangle on both axes
66 T const minX = (this->_x < farX) ? this->_x : farX;
67 T const maxX = (this->_x > farX) ? this->_x : farX;
68 T const minY = (this->_y < farY) ? this->_y : farY;
69 T const maxY = (this->_y > farY) ? this->_y : farY;
70
71 return (point.x >= minX) && (point.x < maxX) && (point.y >= minY) && (point.y < maxY);
72}
73template<class T>
74bool Rect<T>::contains(Rect<T> const& rectangle) const
75{
76 // Rectangles with negative dimensions are allowed, so we must handle them correctly
77 T const r1FarX = static_cast<T>(this->_x + this->_width);
78 T const r1FarY = static_cast<T>(this->_y + this->_height);
79
80 T const r2FarX = static_cast<T>(rectangle._x + rectangle._width);
81 T const r2FarY = static_cast<T>(rectangle._y + rectangle._height);
82
83 // Compute the min and max of the first rectangle on both axes
84 T const r1MinX = (this->_x < r1FarX) ? this->_x : r1FarX;
85 T const r1MaxX = (this->_x > r1FarX) ? this->_x : r1FarX;
86 T const r1MinY = (this->_y < r1FarY) ? this->_y : r1FarY;
87 T const r1MaxY = (this->_y > r1FarY) ? this->_y : r1FarY;
88
89 // Compute the min and max of the second rectangle on both axes
90 T const r2MinX = (rectangle._x < r2FarX) ? rectangle._x : r2FarX;
91 T const r2MaxX = (rectangle._x > r2FarX) ? rectangle._x : r2FarX;
92 T const r2MinY = (rectangle._y < r2FarY) ? rectangle._y : r2FarY;
93 T const r2MaxY = (rectangle._y > r2FarY) ? rectangle._y : r2FarY;
94
95 return (r1MinX <= r2MinX) && (r1MaxX >= r2MaxX) && (r1MinY <= r2MinY) && (r1MaxY >= r2MaxY);
96}
97
98template<class T>
99std::optional<Rect<T>> Rect<T>::findIntersection(Rect<T> const& rectangle) const
100{
101 // Rectangles with negative dimensions are allowed, so we must handle them correctly
102 T const r1FarX = static_cast<T>(this->_x + this->_width);
103 T const r1FarY = static_cast<T>(this->_y + this->_height);
104
105 T const r2FarX = static_cast<T>(rectangle._x + rectangle._width);
106 T const r2FarY = static_cast<T>(rectangle._y + rectangle._height);
107
108 // Compute the min and max of the first rectangle on both axes
109 T const r1MinX = (this->_x < r1FarX) ? this->_x : r1FarX;
110 T const r1MaxX = (this->_x > r1FarX) ? this->_x : r1FarX;
111 T const r1MinY = (this->_y < r1FarY) ? this->_y : r1FarY;
112 T const r1MaxY = (this->_y > r1FarY) ? this->_y : r1FarY;
113
114 // Compute the min and max of the second rectangle on both axes
115 T const r2MinX = (rectangle._x < r2FarX) ? rectangle._x : r2FarX;
116 T const r2MaxX = (rectangle._x > r2FarX) ? rectangle._x : r2FarX;
117 T const r2MinY = (rectangle._y < r2FarY) ? rectangle._y : r2FarY;
118 T const r2MaxY = (rectangle._y > r2FarY) ? rectangle._y : r2FarY;
119
120 // Compute the intersection boundaries
121 T const interLeft = (r1MinX > r2MinX) ? r1MinX : r2MinX;
122 T const interTop = (r1MinY > r2MinY) ? r1MinY : r2MinY;
123 T const interRight = (r1MaxX < r2MaxX) ? r1MaxX : r2MaxX;
124 T const interBottom = (r1MaxY < r2MaxY) ? r1MaxY : r2MaxY;
125
126 // If the intersection is valid (positive non-zero area), then there is an intersection
127 if ((interLeft < interRight) && (interTop < interBottom))
128 {
129 return Rect<T>({interLeft, interTop}, {interRight - interLeft, interBottom - interTop});
130 }
131 return std::nullopt;
132}
133
134template<class T>
135Vector2<T> Rect<T>::getPosition() const
136{
137 return Vector2<T>(this->_x, this->_y);
138}
139
140template<class T>
141Vector2<T> Rect<T>::getSize() const
142{
143 return Vector2<T>(this->_width, this->_height);
144}
145
146inline fge::RectFloat operator*(glm::mat4 const& left, fge::RectFloat const& right)
147{
148 // Transform the 4 corners of the rectangle
149 fge::Vector2f const points[] = {left * glm::vec4(right._x, right._y, 0.0f, 1.0f),
150 left * glm::vec4(right._x, right._y + right._height, 0.0f, 1.0f),
151 left * glm::vec4(right._x + right._width, right._y, 0.0f, 1.0f),
152 left * glm::vec4(right._x + right._width, right._y + right._height, 0.0f, 1.0f)};
153
154 // Compute the bounding rectangle of the transformed points
155 float posLeft = points[0].x;
156 float posTop = points[0].y;
157 float posRight = points[0].x;
158 float posBottom = points[0].y;
159 for (int i = 1; i < 4; ++i)
160 {
161 if (points[i].x < posLeft)
162 {
163 posLeft = points[i].x;
164 }
165 else if (points[i].x > posRight)
166 {
167 posRight = points[i].x;
168 }
169 if (points[i].y < posTop)
170 {
171 posTop = points[i].y;
172 }
173 else if (points[i].y > posBottom)
174 {
175 posBottom = points[i].y;
176 }
177 }
178
179 return fge::RectFloat({posLeft, posTop}, {posRight - posLeft, posBottom - posTop});
180}
181
182} // namespace fge