Atlas - SDL_rect_impl.h

Home / ext / SDL / src / video Lines: 1 | Size: 13349 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from 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 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22// This file is #included twice to support int and float versions with the same code. 23 24static bool SDL_RECT_CAN_OVERFLOW(const RECTTYPE *rect) 25{ 26 if (rect->x <= (SCALARTYPE)(SDL_MIN_SINT32 / 2) || 27 rect->x >= (SCALARTYPE)(SDL_MAX_SINT32 / 2) || 28 rect->y <= (SCALARTYPE)(SDL_MIN_SINT32 / 2) || 29 rect->y >= (SCALARTYPE)(SDL_MAX_SINT32 / 2) || 30 rect->w >= (SCALARTYPE)(SDL_MAX_SINT32 / 2) || 31 rect->h >= (SCALARTYPE)(SDL_MAX_SINT32 / 2)) { 32 return true; 33 } 34 return false; 35} 36 37bool SDL_HASINTERSECTION(const RECTTYPE *A, const RECTTYPE *B) 38{ 39 SCALARTYPE Amin, Amax, Bmin, Bmax; 40 41 CHECK_PARAM(!A) { 42 SDL_InvalidParamError("A"); 43 return false; 44 } 45 CHECK_PARAM(!B) { 46 SDL_InvalidParamError("B"); 47 return false; 48 } 49 CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(A) || SDL_RECT_CAN_OVERFLOW(B)) { 50 SDL_SetError("Potential rect math overflow"); 51 return false; 52 } 53 54 // Horizontal intersection 55 Amin = A->x; 56 Amax = Amin + A->w; 57 Bmin = B->x; 58 Bmax = Bmin + B->w; 59 if (Bmin > Amin) { 60 Amin = Bmin; 61 } 62 if (Bmax < Amax) { 63 Amax = Bmax; 64 } 65 if ((Amax - ENCLOSEPOINTS_EPSILON) < Amin) { 66 return false; 67 } 68 // Vertical intersection 69 Amin = A->y; 70 Amax = Amin + A->h; 71 Bmin = B->y; 72 Bmax = Bmin + B->h; 73 if (Bmin > Amin) { 74 Amin = Bmin; 75 } 76 if (Bmax < Amax) { 77 Amax = Bmax; 78 } 79 if ((Amax - ENCLOSEPOINTS_EPSILON) < Amin) { 80 return false; 81 } 82 return true; 83} 84 85bool SDL_INTERSECTRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result) 86{ 87 SCALARTYPE Amin, Amax, Bmin, Bmax; 88 89 CHECK_PARAM(!A) { 90 SDL_InvalidParamError("A"); 91 return false; 92 } 93 CHECK_PARAM(!B) { 94 SDL_InvalidParamError("B"); 95 return false; 96 } 97 CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(A) || SDL_RECT_CAN_OVERFLOW(B)) { 98 SDL_SetError("Potential rect math overflow"); 99 return false; 100 } 101 CHECK_PARAM(!result) { 102 SDL_InvalidParamError("result"); 103 return false; 104 } 105 106 // Horizontal intersection 107 Amin = A->x; 108 Amax = Amin + A->w; 109 Bmin = B->x; 110 Bmax = Bmin + B->w; 111 if (Bmin > Amin) { 112 Amin = Bmin; 113 } 114 result->x = Amin; 115 if (Bmax < Amax) { 116 Amax = Bmax; 117 } 118 result->w = Amax - Amin; 119 120 // Vertical intersection 121 Amin = A->y; 122 Amax = Amin + A->h; 123 Bmin = B->y; 124 Bmax = Bmin + B->h; 125 if (Bmin > Amin) { 126 Amin = Bmin; 127 } 128 result->y = Amin; 129 if (Bmax < Amax) { 130 Amax = Bmax; 131 } 132 result->h = Amax - Amin; 133 134 return !SDL_RECTEMPTY(result); 135} 136 137bool SDL_UNIONRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result) 138{ 139 SCALARTYPE Amin, Amax, Bmin, Bmax; 140 141 CHECK_PARAM(!A) { 142 return SDL_InvalidParamError("A"); 143 } 144 CHECK_PARAM(!B) { 145 return SDL_InvalidParamError("B"); 146 } 147 CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(A) || SDL_RECT_CAN_OVERFLOW(B)) { 148 return SDL_SetError("Potential rect math overflow"); 149 } 150 CHECK_PARAM(!result) { 151 return SDL_InvalidParamError("result"); 152 } 153 154 if (SDL_RECTEMPTY(A)) { // Special cases for empty Rects 155 if (SDL_RECTEMPTY(B)) { // A and B empty 156 SDL_zerop(result); 157 } else { // A empty, B not empty 158 *result = *B; 159 } 160 return true; 161 } else if (SDL_RECTEMPTY(B)) { // A not empty, B empty 162 *result = *A; 163 return true; 164 } 165 166 // Horizontal union 167 Amin = A->x; 168 Amax = Amin + A->w; 169 Bmin = B->x; 170 Bmax = Bmin + B->w; 171 if (Bmin < Amin) { 172 Amin = Bmin; 173 } 174 result->x = Amin; 175 if (Bmax > Amax) { 176 Amax = Bmax; 177 } 178 result->w = Amax - Amin; 179 180 // Vertical union 181 Amin = A->y; 182 Amax = Amin + A->h; 183 Bmin = B->y; 184 Bmax = Bmin + B->h; 185 if (Bmin < Amin) { 186 Amin = Bmin; 187 } 188 result->y = Amin; 189 if (Bmax > Amax) { 190 Amax = Bmax; 191 } 192 result->h = Amax - Amin; 193 return true; 194} 195 196bool SDL_ENCLOSEPOINTS(const POINTTYPE *points, int count, const RECTTYPE *clip, RECTTYPE *result) 197{ 198 SCALARTYPE minx = 0; 199 SCALARTYPE miny = 0; 200 SCALARTYPE maxx = 0; 201 SCALARTYPE maxy = 0; 202 SCALARTYPE x, y; 203 int i; 204 205 CHECK_PARAM(!points) { 206 SDL_InvalidParamError("points"); 207 return false; 208 } 209 CHECK_PARAM(count < 1) { 210 SDL_InvalidParamError("count"); 211 return false; 212 } 213 214 if (clip) { 215 bool added = false; 216 const SCALARTYPE clip_minx = clip->x; 217 const SCALARTYPE clip_miny = clip->y; 218 const SCALARTYPE clip_maxx = clip->x + clip->w - ENCLOSEPOINTS_EPSILON; 219 const SCALARTYPE clip_maxy = clip->y + clip->h - ENCLOSEPOINTS_EPSILON; 220 221 // Special case for empty rectangle 222 if (SDL_RECTEMPTY(clip)) { 223 return false; 224 } 225 226 for (i = 0; i < count; ++i) { 227 x = points[i].x; 228 y = points[i].y; 229 230 if (x < clip_minx || x > clip_maxx || 231 y < clip_miny || y > clip_maxy) { 232 continue; 233 } 234 if (!added) { 235 // Special case: if no result was requested, we are done 236 if (!result) { 237 return true; 238 } 239 240 // First point added 241 minx = maxx = x; 242 miny = maxy = y; 243 added = true; 244 continue; 245 } 246 if (x < minx) { 247 minx = x; 248 } else if (x > maxx) { 249 maxx = x; 250 } 251 if (y < miny) { 252 miny = y; 253 } else if (y > maxy) { 254 maxy = y; 255 } 256 } 257 if (!added) { 258 return false; 259 } 260 } else { 261 // Special case: if no result was requested, we are done 262 if (!result) { 263 return true; 264 } 265 266 // No clipping, always add the first point 267 minx = maxx = points[0].x; 268 miny = maxy = points[0].y; 269 270 for (i = 1; i < count; ++i) { 271 x = points[i].x; 272 y = points[i].y; 273 274 if (x < minx) { 275 minx = x; 276 } else if (x > maxx) { 277 maxx = x; 278 } 279 if (y < miny) { 280 miny = y; 281 } else if (y > maxy) { 282 maxy = y; 283 } 284 } 285 } 286 287 if (result) { 288 result->x = minx; 289 result->y = miny; 290 result->w = (maxx - minx) + ENCLOSEPOINTS_EPSILON; 291 result->h = (maxy - miny) + ENCLOSEPOINTS_EPSILON; 292 } 293 return true; 294} 295 296// Use the Cohen-Sutherland algorithm for line clipping 297static int COMPUTEOUTCODE(const RECTTYPE *rect, SCALARTYPE x, SCALARTYPE y) 298{ 299 int code = 0; 300 if (y < rect->y) { 301 code |= CODE_TOP; 302 } else if (y > (rect->y + rect->h - ENCLOSEPOINTS_EPSILON)) { 303 code |= CODE_BOTTOM; 304 } 305 if (x < rect->x) { 306 code |= CODE_LEFT; 307 } else if (x > (rect->x + rect->w - ENCLOSEPOINTS_EPSILON)) { 308 code |= CODE_RIGHT; 309 } 310 return code; 311} 312 313bool SDL_INTERSECTRECTANDLINE(const RECTTYPE *rect, SCALARTYPE *X1, SCALARTYPE *Y1, SCALARTYPE *X2, SCALARTYPE *Y2) 314{ 315 SCALARTYPE x = 0; 316 SCALARTYPE y = 0; 317 SCALARTYPE x1, y1; 318 SCALARTYPE x2, y2; 319 SCALARTYPE rectx1; 320 SCALARTYPE recty1; 321 SCALARTYPE rectx2; 322 SCALARTYPE recty2; 323 int outcode1, outcode2; 324 325 CHECK_PARAM(!rect) { 326 SDL_InvalidParamError("rect"); 327 return false; 328 } 329 CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(rect)) { 330 SDL_SetError("Potential rect math overflow"); 331 return false; 332 } 333 CHECK_PARAM(!X1) { 334 SDL_InvalidParamError("X1"); 335 return false; 336 } 337 CHECK_PARAM(!Y1) { 338 SDL_InvalidParamError("Y1"); 339 return false; 340 } 341 CHECK_PARAM(!X2) { 342 SDL_InvalidParamError("X2"); 343 return false; 344 } 345 CHECK_PARAM(!Y2) { 346 SDL_InvalidParamError("Y2"); 347 return false; 348 } 349 350 if (SDL_RECTEMPTY(rect)) { 351 return false; // Special case for empty rect 352 } 353 354 x1 = *X1; 355 y1 = *Y1; 356 x2 = *X2; 357 y2 = *Y2; 358 rectx1 = rect->x; 359 recty1 = rect->y; 360 rectx2 = rect->x + rect->w - ENCLOSEPOINTS_EPSILON; 361 recty2 = rect->y + rect->h - ENCLOSEPOINTS_EPSILON; 362 363 // Check to see if entire line is inside rect 364 if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 && 365 y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) { 366 return true; 367 } 368 369 // Check to see if entire line is to one side of rect 370 if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) || 371 (y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) { 372 return false; 373 } 374 375 if (y1 == y2) { // Horizontal line, easy to clip 376 if (x1 < rectx1) { 377 *X1 = rectx1; 378 } else if (x1 > rectx2) { 379 *X1 = rectx2; 380 } 381 if (x2 < rectx1) { 382 *X2 = rectx1; 383 } else if (x2 > rectx2) { 384 *X2 = rectx2; 385 } 386 return true; 387 } 388 389 if (x1 == x2) { // Vertical line, easy to clip 390 if (y1 < recty1) { 391 *Y1 = recty1; 392 } else if (y1 > recty2) { 393 *Y1 = recty2; 394 } 395 if (y2 < recty1) { 396 *Y2 = recty1; 397 } else if (y2 > recty2) { 398 *Y2 = recty2; 399 } 400 return true; 401 } 402 403 // More complicated Cohen-Sutherland algorithm 404 outcode1 = COMPUTEOUTCODE(rect, x1, y1); 405 outcode2 = COMPUTEOUTCODE(rect, x2, y2); 406 while (outcode1 || outcode2) { 407 if (outcode1 & outcode2) { 408 return false; 409 } 410 411 if (outcode1) { 412 if (outcode1 & CODE_TOP) { 413 y = recty1; 414 x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1)); 415 } else if (outcode1 & CODE_BOTTOM) { 416 y = recty2; 417 x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1)); 418 } else if (outcode1 & CODE_LEFT) { 419 x = rectx1; 420 y = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(y2 - y1) * (x - x1)) / (x2 - x1)); 421 } else if (outcode1 & CODE_RIGHT) { 422 x = rectx2; 423 y = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(y2 - y1) * (x - x1)) / (x2 - x1)); 424 } 425 x1 = x; 426 y1 = y; 427 outcode1 = COMPUTEOUTCODE(rect, x, y); 428 } else { 429 if (outcode2 & CODE_TOP) { 430 SDL_assert(y2 != y1); // if equal: division by zero. 431 y = recty1; 432 x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1)); 433 } else if (outcode2 & CODE_BOTTOM) { 434 SDL_assert(y2 != y1); // if equal: division by zero. 435 y = recty2; 436 x = (SCALARTYPE) (x1 + ((BIGSCALARTYPE)(x2 - x1) * (y - y1)) / (y2 - y1)); 437 } else if (outcode2 & CODE_LEFT) { 438 /* If this assertion ever fires, here's the static analysis that warned about it: 439 http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */ 440 SDL_assert(x2 != x1); // if equal: division by zero. 441 x = rectx1; 442 y = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(y2 - y1) * (x - x1)) / (x2 - x1)); 443 } else if (outcode2 & CODE_RIGHT) { 444 /* If this assertion ever fires, here's the static analysis that warned about it: 445 http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */ 446 SDL_assert(x2 != x1); // if equal: division by zero. 447 x = rectx2; 448 y = (SCALARTYPE) (y1 + ((BIGSCALARTYPE)(y2 - y1) * (x - x1)) / (x2 - x1)); 449 } 450 x2 = x; 451 y2 = y; 452 outcode2 = COMPUTEOUTCODE(rect, x, y); 453 } 454 } 455 *X1 = x1; 456 *Y1 = y1; 457 *X2 = x2; 458 *Y2 = y2; 459 return true; 460} 461 462#undef RECTTYPE 463#undef POINTTYPE 464#undef SCALARTYPE 465#undef BIGSCALARTYPE 466#undef COMPUTEOUTCODE 467#undef ENCLOSEPOINTS_EPSILON 468#undef SDL_RECT_CAN_OVERFLOW 469#undef SDL_HASINTERSECTION 470#undef SDL_INTERSECTRECT 471#undef SDL_RECTEMPTY 472#undef SDL_UNIONRECT 473#undef SDL_ENCLOSEPOINTS 474#undef SDL_INTERSECTRECTANDLINE 475
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.