1 /*
2     DSDL
3     Copyright (C) 2025 Inochi2D Project <luna@foxgirls.gay>
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 
23     Simple DirectMedia Layer
24     Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
25 
26     This software is provided 'as-is', without any express or implied
27     warranty.  In no event will the authors be held liable for any damages
28     arising from the use of this software.
29 
30     Permission is granted to anyone to use this software for any purpose,
31     including commercial applications, and to alter it and redistribute it
32     freely, subject to the following restrictions:
33 
34     1. The origin of this software must not be misrepresented; you must not
35         claim that you wrote the original software. If you use this software
36         in a product, an acknowledgment in the product documentation would be
37         appreciated but is not required.
38     2. Altered source versions must be plainly marked as such, and must not be
39         misrepresented as being the original software.
40     3. This notice may not be removed or altered from any source distribution.
41 */
42 
43 /**
44     SDL Rects
45 
46     See_Also:
47         $(LINK2 https://wiki.libsdl.org/SDL3/CategoryRect, SDL3 Rect Documentation)
48 
49     Copyright: © 2025 Inochi2D Project, © 1997-2025 Sam Lantinga
50     License: Subject to the terms of the Zlib License, as written in the LICENSE file.
51     Authors: 
52         Luna Nielsen
53 */
54 module sdl.rect;
55 import sdl.stdc;
56 import core.stdc.math;
57 import core.stdc.float_;
58 
59 extern(C) nothrow @nogc:
60 
61 /**
62     The structure that defines a point (using integers).
63 
64     See_Also:
65         $(D SDL_GetRectEnclosingPoints)
66         $(D SDL_PointInRect)
67 */
68 struct SDL_Point {
69     int x;
70     int y;
71 }
72 
73 /**
74     The structure that defines a point (using floating point values).
75 
76     See_Also:
77         $(D SDL_GetRectEnclosingPointsFloat)
78         $(D SDL_PointInRectFloat)
79 */
80 struct SDL_FPoint {
81     float x;
82     float y;
83 }
84 
85 
86 /**
87     A rectangle, with the origin at the upper left (using integers).
88 
89     See_Also:
90         $(D SDL_RectEmpty)
91         $(D SDL_RectsEqual)
92         $(D SDL_HasRectIntersection)
93         $(D SDL_GetRectIntersection)
94         $(D SDL_GetRectAndLineIntersection)
95         $(D SDL_GetRectUnion)
96         $(D SDL_GetRectEnclosingPoints)
97 */
98 struct SDL_Rect {
99     int x, y;
100     int w, h;
101 }
102 
103 
104 /**
105     A rectangle, with the origin at the upper left (using floating point
106     values).
107 
108     See_Also:
109         $(D SDL_RectEmptyFloat)
110         $(D SDL_RectsEqualFloat)
111         $(D SDL_RectsEqualEpsilon)
112         $(D SDL_HasRectIntersectionFloat)
113         $(D SDL_GetRectIntersectionFloat)
114         $(D SDL_GetRectAndLineIntersectionFloat)
115         $(D SDL_GetRectUnionFloat)
116         $(D SDL_GetRectEnclosingPointsFloat)
117         $(D SDL_PointInRectFloat)
118 */
119 struct SDL_FRect {
120     float x;
121     float y;
122     float w;
123     float h;
124 }
125 
126 
127 /**
128     Convert an SDL_Rect to SDL_FRect
129     
130     Params:
131         rect =  a pointer to an SDL_Rect.
132         frect = a pointer filled in with the floating point representation of
133                 `rect`.
134     
135     Threadsafety:
136         It is safe to call this function from any thread.
137 */
138 pragma(inline, true)
139 void SDL_RectToFRect(const(SDL_Rect)* rect, SDL_FRect* frect) {
140     frect.x = cast(float)rect.x;
141     frect.y = cast(float)rect.y;
142     frect.w = cast(float)rect.w;
143     frect.h = cast(float)rect.h;
144 }
145 
146 /**
147     Determine whether a point resides inside a rectangle.
148 
149     A point is considered part of a rectangle if both `p` and `r` are not NULL,
150     and `p`'s x and y coordinates are >= to the rectangle's top left corner,
151     and < the rectangle's x+w and y+h. So a 1x1 rectangle considers point (0,0)
152     as "inside" and (0,1) as not.
153 
154     Note that this is a forced-inline function in a header, and not a public
155     API function available in the SDL library (which is to say, the code is
156     embedded in the calling program and the linker and dynamic loader will not
157     be able to find this function inside SDL itself).
158 
159     Params:
160         p = the point to test.
161         r = the rectangle to test.
162     
163     Returns:
164         true if `p` is contained by `r`, false otherwise.
165 
166     Threadsafety:
167         It is safe to call this function from any thread.
168 */
169 pragma(inline, true)
170 bool SDL_PointInRect(const(SDL_Point)* p, const(SDL_Rect)* r) {
171     return ( p && r && (p.x >= r.x) && (p.x < (r.x + r.w)) &&
172              (p.y >= r.y) && (p.y < (r.y + r.h)) ) ? true : false;
173 }
174 
175 /**
176     Determine whether a rectangle has no area.
177 
178     A rectangle is considered "empty" for this function if `r` is NULL, or if
179     `r`'s width and/or height are <= 0.
180 
181     Note that this is a forced-inline function in a header, and not a public
182     API function available in the SDL library (which is to say, the code is
183     embedded in the calling program and the linker and dynamic loader will not
184     be able to find this function inside SDL itself).
185 
186     Params:
187         r = the rectangle to test.
188     
189     Returns:
190         true if the rectangle is "empty", false otherwise.
191 
192     Threadsafety:
193         It is safe to call this function from any thread.
194 
195 */
196 pragma(inline, true)
197 bool SDL_RectEmpty(const(SDL_Rect)* r) {
198     return ((!r) || (r.w <= 0) || (r.h <= 0)) ? true : false;
199 }
200 
201 /**
202     Determine whether two rectangles are equal.
203 
204     Rectangles are considered equal if both are not NULL and each of their x,
205     y, width and height match.
206 
207     Note that this is a forced-inline function in a header, and not a public
208     API function available in the SDL library (which is to say, the code is
209     embedded in the calling program and the linker and dynamic loader will not
210     be able to find this function inside SDL itself).
211 
212     Params:
213         a = the first rectangle to test.
214         b = the second rectangle to test.
215     
216     Returns:
217         true if the rectangles are equal, false otherwise.
218 
219     Threadsafety:
220         It is safe to call this function from any thread.
221 
222 */
223 pragma(inline, true)
224 bool SDL_RectsEqual(const(SDL_Rect)* a, const(SDL_Rect)* b) {
225     return (a && b && (a.x == b.x) && (a.y == b.y) &&
226             (a.w == b.w) && (a.h == b.h)) ? true : false;
227 }
228 
229 /**
230     Determine whether two rectangles intersect.
231 
232     If either pointer is NULL the function will return false.
233 
234     Params:
235         A = an SDL_Rect structure representing the first rectangle.
236         B = an SDL_Rect structure representing the second rectangle.
237     
238     Returns:
239         true if there is an intersection, false otherwise.
240 
241     Threadsafety:
242         It is safe to call this function from any thread.
243 
244 
245     \sa SDL_GetRectIntersection
246 */
247 extern bool SDL_HasRectIntersection(const(SDL_Rect)* A, const(SDL_Rect)* B);
248 
249 /**
250     Calculate the intersection of two rectangles.
251 
252     If `result` is NULL then this function will return false.
253 
254     Params:
255         A =         an SDL_Rect structure representing the first rectangle.
256         B =         an SDL_Rect structure representing the second rectangle.
257         result =    an SDL_Rect structure filled in with the intersection of
258                     rectangles `A` and `B`.
259     
260     Returns:
261         true if there is an intersection, false otherwise.
262 
263     See_Also:
264         $(D SDL_HasRectIntersection)
265 */
266 extern bool SDL_GetRectIntersection(const(SDL_Rect)* A, const(SDL_Rect)* B, SDL_Rect* result);
267 
268 /**
269     Calculate the union of two rectangles.
270 
271     Params:
272         A =         an SDL_Rect structure representing the first rectangle.
273         B =         an SDL_Rect structure representing the second rectangle.
274         result =    an SDL_Rect structure filled in with the union of rectangles
275                     `A` and `B`.
276     Returns:
277         true on success or false on failure; call SDL_GetError() for more
278             information.
279 
280 */
281 extern bool SDL_GetRectUnion(const(SDL_Rect)* A, const(SDL_Rect)* B, SDL_Rect* result);
282 
283 /**
284     Calculate a minimal rectangle enclosing a set of points.
285 
286     If `clip` is not NULL then only points inside of the clipping rectangle are
287     considered.
288 
289     Params:
290         points =    an array of SDL_Point structures representing points to be
291                     enclosed.
292         count =     the number of structures in the `points` array.
293         clip =      an SDL_Rect used for clipping or NULL to enclose all points.
294         result =    an SDL_Rect structure filled in with the minimal enclosing
295                     rectangle.
296     
297     Returns:
298         true if any points were enclosed or false if all the points were
299             outside of the clipping rectangle.
300 
301 */
302 extern bool SDL_GetRectEnclosingPoints(const(SDL_Point)* points, int count, const(SDL_Rect)* clip, SDL_Rect* result);
303 
304 /**
305     Calculate the intersection of a rectangle and line segment.
306 
307     This function is used to clip a line segment to a rectangle. A line segment
308     contained entirely within the rectangle or that does not intersect will
309     remain unchanged. A line segment that crosses the rectangle at either or
310     both ends will be clipped to the boundary of the rectangle and the new
311     coordinates saved in `X1`, `Y1`, `X2`, and/or `Y2` as necessary.
312 
313     Params:
314         rect =  an SDL_Rect structure representing the rectangle to intersect.
315         X1 =    a pointer to the starting X-coordinate of the line.
316         Y1 =    a pointer to the starting Y-coordinate of the line.
317         X2 =    a pointer to the ending X-coordinate of the line.
318         Y2 =    a pointer to the ending Y-coordinate of the line.
319 
320     Returns:
321         true if there is an intersection, false otherwise.
322 
323 */
324 extern bool SDL_GetRectAndLineIntersection(const(SDL_Rect)* rect, int* X1, int* Y1, int* X2, int* Y2);
325 
326 
327 /* SDL_FRect versions... */
328 
329 /**
330     Determine whether a point resides inside a floating point rectangle.
331 
332     A point is considered part of a rectangle if both `p` and `r` are not NULL,
333     and `p`'s x and y coordinates are >= to the rectangle's top left corner,
334     and <= the rectangle's x+w and y+h. So a 1x1 rectangle considers point
335     (0,0) and (0,1) as "inside" and (0,2) as not.
336 
337     Note that this is a forced-inline function in a header, and not a public
338     API function available in the SDL library (which is to say, the code is
339     embedded in the calling program and the linker and dynamic loader will not
340     be able to find this function inside SDL itself).
341 
342     Params:
343         p = the point to test.
344         r = the rectangle to test.
345     
346     Returns:
347         true if `p` is contained by `r`, false otherwise.
348 
349     Threadsafety:
350         It is safe to call this function from any thread.
351 
352 */
353 pragma(inline, true)
354 bool SDL_PointInRectFloat(const(SDL_FPoint)* p, const(SDL_FRect)* r) {
355     return ( p && r && (p.x >= r.x) && (p.x <= (r.x + r.w)) &&
356              (p.y >= r.y) && (p.y <= (r.y + r.h)) ) ? true : false;
357 }
358 
359 /**
360     Determine whether a floating point rectangle can contain any point.
361 
362     A rectangle is considered "empty" for this function if `r` is NULL, or if
363     `r`'s width and/or height are < 0.0f.
364 
365     Note that this is a forced-inline function in a header, and not a public
366     API function available in the SDL library (which is to say, the code is
367     embedded in the calling program and the linker and dynamic loader will not
368     be able to find this function inside SDL itself).
369 
370     Params:
371         r = the rectangle to test.
372 
373     Returns:
374         true if the rectangle is "empty", false otherwise.
375 
376     Threadsafety:
377         It is safe to call this function from any thread.
378 
379 */
380 pragma(inline, true)
381 bool SDL_RectEmptyFloat(const(SDL_FRect)* r) {
382     return ((!r) || (r.w < 0.0f) || (r.h < 0.0f)) ? true : false;
383 }
384 
385 /**
386     Determine whether two floating point rectangles are equal, within some
387     given epsilon.
388 
389     Rectangles are considered equal if both are not NULL and each of their x,
390     y, width and height are within `epsilon` of each other. If you don't know
391     what value to use for `epsilon`, you should call the SDL_RectsEqualFloat
392     function instead.
393 
394     Note that this is a forced-inline function in a header, and not a public
395     API function available in the SDL library (which is to say, the code is
396     embedded in the calling program and the linker and dynamic loader will not
397     be able to find this function inside SDL itself).
398 
399     Params:
400         a =         the first rectangle to test.
401         b =         the second rectangle to test.
402         epsilon =   the epsilon value for comparison.
403     
404     Returns:
405         true if the rectangles are equal, false otherwise.
406 
407     Threadsafety:
408         It is safe to call this function from any thread.
409 
410     See_Also:
411         $(D SDL_RectsEqualFloat)
412 */
413 pragma(inline, true)
414 bool SDL_RectsEqualEpsilon(const(SDL_FRect)* a, const(SDL_FRect)* b, const(float) epsilon) {
415     return (a && b && ((a == b) ||
416             ((fabsf(a.x - b.x) <= epsilon) &&
417             (fabsf(a.y - b.y) <= epsilon) &&
418             (fabsf(a.w - b.w) <= epsilon) &&
419             (fabsf(a.h - b.h) <= epsilon))))
420             ? true : false;
421 }
422 
423 /**
424     Determine whether two floating point rectangles are equal, within a default
425     epsilon.
426 
427     Rectangles are considered equal if both are not NULL and each of their x,
428     y, width and height are within SDL_FLT_EPSILON of each other. This is often
429     a reasonable way to compare two floating point rectangles and deal with the
430     slight precision variations in floating point calculations that tend to pop
431     up.
432 
433     Note that this is a forced-inline function in a header, and not a public
434     API function available in the SDL library (which is to say, the code is
435     embedded in the calling program and the linker and dynamic loader will not
436     be able to find this function inside SDL itself).
437 
438     Params:
439         a = the first rectangle to test.
440         b = the second rectangle to test.
441     
442     Returns:
443         true if the rectangles are equal, false otherwise.
444 
445     Threadsafety:
446         It is safe to call this function from any thread.
447 
448 
449     \sa SDL_RectsEqualEpsilon
450 */
451 pragma(inline, true)
452 bool SDL_RectsEqualFloat(const(SDL_FRect)* a, const(SDL_FRect)* b) {
453     return SDL_RectsEqualEpsilon(a, b, FLT_EPSILON);
454 }
455 
456 /**
457     Determine whether two rectangles intersect with float precision.
458 
459     If either pointer is NULL the function will return false.
460 
461     Params:
462         A = an SDL_FRect structure representing the first rectangle.
463         B = an SDL_FRect structure representing the second rectangle.
464     
465     Returns:
466         true if there is an intersection, false otherwise.
467 
468     See_Also:
469         $(D SDL_GetRectIntersection)
470 */
471 extern bool SDL_HasRectIntersectionFloat(const(SDL_FRect)* A, const(SDL_FRect)* B);
472 
473 /**
474     Calculate the intersection of two rectangles with float precision.
475 
476     If `result` is NULL then this function will return false.
477 
478     Params:
479         A =         an SDL_FRect structure representing the first rectangle.
480         B =         an SDL_FRect structure representing the second rectangle.
481         result =    an SDL_FRect structure filled in with the intersection of
482                     rectangles `A` and `B`.
483     
484     Returns:
485         true if there is an intersection, false otherwise.
486 
487 
488     \sa SDL_HasRectIntersectionFloat
489 */
490 extern bool SDL_GetRectIntersectionFloat(const(SDL_FRect)* A, const(SDL_FRect)* B, SDL_FRect* result);
491 
492 /**
493     Calculate the union of two rectangles with float precision.
494 
495     Params:
496         A =         an SDL_FRect structure representing the first rectangle.
497         B =         an SDL_FRect structure representing the second rectangle.
498         result =    an SDL_FRect structure filled in with the union of rectangles
499                     `A` and `B`.
500     
501     Returns:
502         true on success or false on failure; call SDL_GetError() for more
503             information.
504 
505 */
506 extern bool SDL_GetRectUnionFloat(const(SDL_FRect)* A, const(SDL_FRect)* B, SDL_FRect* result);
507 
508 /**
509     Calculate a minimal rectangle enclosing a set of points with float
510     precision.
511 
512     If `clip` is not NULL then only points inside of the clipping rectangle are
513     considered.
514 
515     Params:
516         points =    an array of SDL_FPoint structures representing points to be
517                     enclosed.
518         count =     the number of structures in the `points` array.
519         clip =      an SDL_FRect used for clipping or NULL to enclose all points.
520         result =    an SDL_FRect structure filled in with the minimal enclosing
521                     rectangle.
522     
523     Returns:
524         true if any points were enclosed or false if all the points were
525         outside of the clipping rectangle.
526 
527 */
528 extern bool SDL_GetRectEnclosingPointsFloat(const(SDL_FPoint)* points, int count, const(SDL_FRect)* clip, SDL_FRect* result);
529 
530 /**
531     Calculate the intersection of a rectangle and line segment with float
532     precision.
533     
534     This function is used to clip a line segment to a rectangle. A line segment
535     contained entirely within the rectangle or that does not intersect will
536     remain unchanged. A line segment that crosses the rectangle at either or
537     both ends will be clipped to the boundary of the rectangle and the new
538     coordinates saved in `X1`, `Y1`, `X2`, and/or `Y2` as necessary.
539     
540     Params:
541         rect =  an SDL_FRect structure representing the rectangle to intersect.
542         X1 =    a pointer to the starting X-coordinate of the line.
543         Y1 =    a pointer to the starting Y-coordinate of the line.
544         X2 =    a pointer to the ending X-coordinate of the line.
545         Y2 =    a pointer to the ending Y-coordinate of the line.
546         
547     Returns:
548         true if there is an intersection, false otherwise.
549     
550 */
551 extern bool SDL_GetRectAndLineIntersectionFloat(const(SDL_FRect)* rect, float* X1, float* Y1, float* X2, float* Y2);