1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Math.Rect; 25 26 private: 27 28 import derelict.sdl2.sdl; 29 30 import Dgame.Math.Vector2; 31 32 package(Dgame): 33 34 @nogc 35 SDL_Rect* _transfer(ref const Rect rect, ref SDL_Rect to) pure nothrow { 36 to.x = rect.x; 37 to.y = rect.y; 38 to.w = rect.width; 39 to.h = rect.height; 40 41 return &to; 42 } 43 44 public: 45 46 /** 47 * Size contains a width and a height property and 48 * is used to wraps both, the width and the height, in one element. 49 */ 50 struct Size { 51 /** 52 * the width property 53 */ 54 uint width; 55 /** 56 * the height property 57 */ 58 uint height; 59 } 60 61 /** 62 * Rect defines a rectangle structure that contains the left upper corner and the width/height. 63 * 64 * Author: Randy Schuett (rswhite4@googlemail.com) 65 */ 66 struct Rect { 67 /** 68 * The edges of the Rectangle 69 */ 70 enum Edge : ubyte { 71 Top, /// Top edge 72 Bottom, /// Bottom edge 73 Left, /// Left edge 74 Right, /// Right edge 75 76 TopLeft, /// TopLeft edge 77 TopRight, /// TopRight edge 78 BottomLeft, /// BottomLeft edge 79 BottomRight /// BottomRight edge 80 } 81 82 /** 83 * The x coordinate 84 */ 85 int x = 0; 86 /** 87 * The y coordinates 88 */ 89 int y = 0; 90 /** 91 * The width 92 */ 93 uint width = 0; 94 /** 95 * The height 96 */ 97 uint height = 0; 98 99 /** 100 * CTor 101 */ 102 @nogc 103 this(int x, int y, uint width, uint height) pure nothrow { 104 this.x = x; 105 this.y = y; 106 this.width = width; 107 this.height = height; 108 } 109 110 /** 111 * Supported operations: +, -, *, /, % 112 */ 113 @nogc 114 Rect opBinary(string op)(const Rect rect) const pure nothrow { 115 switch (op) { 116 case "+": 117 case "-": 118 case "*": 119 case "/": 120 case "%": 121 mixin("return Rect(this.x " ~ op ~ " rect.x, 122 this.y " ~ op ~ " rect.y, 123 this.width " ~ op ~ " rect.width, 124 this.height " ~ op ~ " rect.height);"); 125 default: 126 assert(0, "Unsupported Operation: " ~ op); 127 } 128 } 129 130 /** 131 * Collapse this Rect. Means that the size is set to 0. 132 */ 133 @nogc 134 void collapse() pure nothrow { 135 this.width = this.height = 0; 136 } 137 138 /** 139 * Checks if this Rect is empty (if it's collapsed) with SDL_RectEmpty. 140 */ 141 @nogc 142 bool isEmpty() const pure nothrow { 143 return this.width == 0 || this.height == 0; 144 } 145 146 /** 147 * Returns an union of the given and this Rect. 148 */ 149 @nogc 150 Rect getUnion(const Rect rect) const { 151 SDL_Rect a = void; 152 SDL_Rect b = void; 153 SDL_Rect c = void; 154 155 SDL_UnionRect(_transfer(this, a), _transfer(rect, b), &c); 156 157 return Rect(c.x, c.y, c.w, c.h); 158 } 159 160 /** 161 * Checks whether this Rect contains the given coordinates. 162 */ 163 @nogc 164 bool contains(const Vector2i vec) const pure nothrow { 165 return this.contains(vec.x, vec.y); 166 } 167 168 /** 169 * Checks whether this Rect contains the given coordinates. 170 */ 171 @nogc 172 bool contains(int x, int y) const pure nothrow { 173 return (x >= this.x) && (x < this.x + this.width) && (y >= this.y) && (y < this.y + this.height); 174 } 175 176 /** 177 * opEquals: compares two rectangles on their coordinates and their size (but not explicit type). 178 */ 179 @nogc 180 bool opEquals(const Rect rect) const pure nothrow { 181 return this.x == rect.x && this.y == rect.y && this.width == rect.width && this.height == rect.height; 182 } 183 184 /** 185 * Checks whether this Rect intersects with an other. 186 * If, and the parameter 'overlap' isn't null, 187 * the colliding rectangle is stored there. 188 */ 189 @nogc 190 bool intersects(const Rect rect, Rect* overlap = null) const { 191 SDL_Rect a = void; 192 SDL_Rect b = void; 193 194 if (!overlap) 195 return SDL_HasIntersection(_transfer(this, a), _transfer(rect, b)) == SDL_TRUE; 196 197 SDL_Rect c = void; 198 199 immutable bool intersects = SDL_IntersectRect(_transfer(this, a), _transfer(rect, b), &c) == SDL_TRUE; 200 201 overlap.x = c.x; 202 overlap.y = c.y; 203 overlap.width = c.w; 204 overlap.height = c.h; 205 206 return intersects; 207 } 208 209 /** 210 * Replace the current size. 211 */ 212 @nogc 213 void setSize(uint width, uint height) pure nothrow { 214 this.width = width; 215 this.height = height; 216 } 217 218 /** 219 * Replace the current size. 220 */ 221 @nogc 222 void setSize(const Size size) pure nothrow { 223 this.setSize(size.width, size.height); 224 } 225 226 /** 227 * Returns the current size as Vector2 228 */ 229 @nogc 230 Size getSize() const pure nothrow { 231 return Size(this.width, this.height); 232 } 233 234 /** 235 * Increase current size. 236 */ 237 @nogc 238 void increase(int width, int height) pure nothrow { 239 this.width += width; 240 this.height += height; 241 } 242 243 /** 244 * Set a new position with coordinates. 245 */ 246 @nogc 247 void setPosition(int x, int y) pure nothrow { 248 this.x = x; 249 this.y = y; 250 } 251 252 /** 253 * Set a new position with a vector. 254 */ 255 @nogc 256 void setPosition(const Vector2i position) pure nothrow { 257 this.setPosition(position.x, position.y); 258 } 259 260 /** 261 * Returns the current position as Vector2 262 */ 263 @nogc 264 Vector2i getPosition() const pure nothrow { 265 return Vector2i(this.x, this.y); 266 } 267 268 /** 269 * Move the object. 270 */ 271 @nogc 272 void move(const Vector2i vec) pure nothrow { 273 this.move(vec.x, vec.y); 274 } 275 276 /** 277 * Move the object. 278 */ 279 @nogc 280 void move(int x, int y) pure nothrow { 281 this.x += x; 282 this.y += y; 283 } 284 285 /** 286 * Returns the position of the given Edge on this Rect. 287 */ 288 @nogc 289 Vector2i getEdgePosition(Edge edge) const pure nothrow { 290 Vector2i pos; 291 final switch (edge) { 292 case Edge.Top: 293 pos.x = this.x + (this.width / 2); 294 pos.y = this.y; 295 break; 296 case Edge.Bottom: 297 pos.x = this.x + (this.width / 2); 298 pos.y = this.y + this.height; 299 break; 300 case Edge.Left: 301 pos.x = this.x; 302 pos.y = this.y + (this.height / 2); 303 break; 304 case Edge.Right: 305 pos.x = this.x + this.width; 306 pos.y = this.y + (this.height / 2); 307 break; 308 case Edge.TopLeft: 309 pos.x = this.x; 310 pos.y = this.y; 311 break; 312 case Edge.TopRight: 313 pos.x = this.x + this.width; 314 pos.y = this.y; 315 break; 316 case Edge.BottomLeft: 317 pos.x = this.x; 318 pos.y = this.y + this.height; 319 break; 320 case Edge.BottomRight: 321 pos.x = this.x + this.width; 322 pos.y = this.y + this.height; 323 break; 324 } 325 326 return pos; 327 } 328 329 /** 330 * Returns the center position of this Rect 331 */ 332 @nogc 333 Vector2i getCenter() const pure nothrow { 334 return Vector2i(this.x + (this.width / 2), this.y + (this.height / 2)); 335 } 336 }