mirror of https://github.com/encounter/SDL.git
SDL_Rect: Added floating point versions of all the rectangle APIs.
Fixes #5110.
This commit is contained in:
parent
4d9bef604a
commit
d81fee7623
|
@ -54,8 +54,13 @@ typedef struct SDL_Point
|
|||
/**
|
||||
* The structure that defines a point (floating point)
|
||||
*
|
||||
* \sa SDL_EnclosePoints
|
||||
* \sa SDL_PointInRect
|
||||
* \sa SDL_FRectEmpty
|
||||
* \sa SDL_FRectEquals
|
||||
* \sa SDL_HasIntersectionF
|
||||
* \sa SDL_IntersectFRect
|
||||
* \sa SDL_UnionFRect
|
||||
* \sa SDL_EncloseFPoints
|
||||
* \sa SDL_PointInFRect
|
||||
*/
|
||||
typedef struct SDL_FPoint
|
||||
{
|
||||
|
@ -213,6 +218,119 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IntersectRectAndLine(const SDL_Rect *
|
|||
int *Y1, int *X2,
|
||||
int *Y2);
|
||||
|
||||
|
||||
/* SDL_FRect versions... */
|
||||
|
||||
/**
|
||||
* Returns true if point resides inside a rectangle.
|
||||
*/
|
||||
SDL_FORCE_INLINE SDL_bool SDL_PointInFRect(const SDL_FPoint *p, const SDL_FRect *r)
|
||||
{
|
||||
return ( (p->x >= r->x) && (p->x < (r->x + r->w)) &&
|
||||
(p->y >= r->y) && (p->y < (r->y + r->h)) ) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the rectangle has no area.
|
||||
*/
|
||||
SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r)
|
||||
{
|
||||
return ((!r) || (r->w <= 0.0f) || (r->h <= 0.0f)) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the two rectangles are equal.
|
||||
*/
|
||||
SDL_FORCE_INLINE SDL_bool SDL_FRectEquals(const SDL_FRect *a, const SDL_FRect *b)
|
||||
{
|
||||
return (a && b && (a->x == b->x) && (a->y == b->y) &&
|
||||
(a->w == b->w) && (a->h == b->h)) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether two rectangles intersect with float precision.
|
||||
*
|
||||
* If either pointer is NULL the function will return SDL_FALSE.
|
||||
*
|
||||
* \param A an SDL_FRect structure representing the first rectangle
|
||||
* \param B an SDL_FRect structure representing the second rectangle
|
||||
* \returns SDL_TRUE if there is an intersection, SDL_FALSE otherwise.
|
||||
*
|
||||
* \sa SDL_IntersectRect
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_HasIntersectionF(const SDL_FRect * A,
|
||||
const SDL_FRect * B);
|
||||
|
||||
/**
|
||||
* Calculate the intersection of two rectangles with float precision.
|
||||
*
|
||||
* If `result` is NULL then this function will return SDL_FALSE.
|
||||
*
|
||||
* \param A an SDL_FRect structure representing the first rectangle
|
||||
* \param B an SDL_FRect structure representing the second rectangle
|
||||
* \param result an SDL_FRect structure filled in with the intersection of
|
||||
* rectangles `A` and `B`
|
||||
* \returns SDL_TRUE if there is an intersection, SDL_FALSE otherwise.
|
||||
*
|
||||
* \sa SDL_HasIntersectionF
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_IntersectFRect(const SDL_FRect * A,
|
||||
const SDL_FRect * B,
|
||||
SDL_FRect * result);
|
||||
|
||||
/**
|
||||
* Calculate the union of two rectangles with float precision.
|
||||
*
|
||||
* \param A an SDL_FRect structure representing the first rectangle
|
||||
* \param B an SDL_FRect structure representing the second rectangle
|
||||
* \param result an SDL_FRect structure filled in with the union of rectangles
|
||||
* `A` and `B`
|
||||
*/
|
||||
extern DECLSPEC void SDLCALL SDL_UnionFRect(const SDL_FRect * A,
|
||||
const SDL_FRect * B,
|
||||
SDL_FRect * result);
|
||||
|
||||
/**
|
||||
* Calculate a minimal rectangle enclosing a set of points with float precision.
|
||||
*
|
||||
* If `clip` is not NULL then only points inside of the clipping rectangle are
|
||||
* considered.
|
||||
*
|
||||
* \param points an array of SDL_FPoint structures representing points to be
|
||||
* enclosed
|
||||
* \param count the number of structures in the `points` array
|
||||
* \param clip an SDL_FRect used for clipping or NULL to enclose all points
|
||||
* \param result an SDL_FRect structure filled in with the minimal enclosing
|
||||
* rectangle
|
||||
* \returns SDL_TRUE if any points were enclosed or SDL_FALSE if all the
|
||||
* points were outside of the clipping rectangle.
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_EncloseFPoints(const SDL_FPoint * points,
|
||||
int count,
|
||||
const SDL_FRect * clip,
|
||||
SDL_FRect * result);
|
||||
|
||||
/**
|
||||
* Calculate the intersection of a rectangle and line segment with float precision.
|
||||
*
|
||||
* This function is used to clip a line segment to a rectangle. A line segment
|
||||
* contained entirely within the rectangle or that does not intersect will
|
||||
* remain unchanged. A line segment that crosses the rectangle at either or
|
||||
* both ends will be clipped to the boundary of the rectangle and the new
|
||||
* coordinates saved in `X1`, `Y1`, `X2`, and/or `Y2` as necessary.
|
||||
*
|
||||
* \param rect an SDL_FRect structure representing the rectangle to intersect
|
||||
* \param X1 a pointer to the starting X-coordinate of the line
|
||||
* \param Y1 a pointer to the starting Y-coordinate of the line
|
||||
* \param X2 a pointer to the ending X-coordinate of the line
|
||||
* \param Y2 a pointer to the ending Y-coordinate of the line
|
||||
* \returns SDL_TRUE if there is an intersection, SDL_FALSE otherwise.
|
||||
*/
|
||||
extern DECLSPEC SDL_bool SDLCALL SDL_IntersectFRectAndLine(const SDL_FRect *
|
||||
rect, float *X1,
|
||||
float *Y1, float *X2,
|
||||
float *Y2);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -859,3 +859,8 @@
|
|||
#define SDL_GetTouchName SDL_GetTouchName_REAL
|
||||
#define SDL_ClearComposition SDL_ClearComposition_REAL
|
||||
#define SDL_IsTextInputShown SDL_IsTextInputShown_REAL
|
||||
#define SDL_HasIntersectionF SDL_HasIntersectionF_REAL
|
||||
#define SDL_IntersectFRect SDL_IntersectFRect_REAL
|
||||
#define SDL_UnionFRect SDL_UnionFRect_REAL
|
||||
#define SDL_EncloseFPoints SDL_EncloseFPoints_REAL
|
||||
#define SDL_IntersectFRectAndLine SDL_IntersectFRectAndLine_REAL
|
||||
|
|
|
@ -930,3 +930,8 @@ SDL_DYNAPI_PROC(int,SDL_AndroidSendMessage,(Uint32 a, int b),(a,b),return)
|
|||
SDL_DYNAPI_PROC(const char*,SDL_GetTouchName,(int a),(a),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_ClearComposition,(void),(),)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_IsTextInputShown,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_HasIntersectionF,(const SDL_FRect *a, const SDL_FRect *b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRect,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(void,SDL_UnionFRect,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_EncloseFPoints,(const SDL_FPoint *a, int b, const SDL_FRect *c, SDL_FRect *d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRectAndLine,(const SDL_FRect *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return)
|
||||
|
|
|
@ -3382,60 +3382,6 @@ SDL_RenderFillRectsF(SDL_Renderer * renderer,
|
|||
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
|
||||
}
|
||||
|
||||
/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */
|
||||
SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r)
|
||||
{
|
||||
return ((!r) || (r->w <= 0.0f) || (r->h <= 0.0f)) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */
|
||||
static SDL_bool
|
||||
SDL_HasIntersectionF(const SDL_FRect * A, const SDL_FRect * B)
|
||||
{
|
||||
float Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Special cases for empty rects */
|
||||
if (SDL_FRectEmpty(A) || SDL_FRectEmpty(B)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Horizontal intersection */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin > Amin)
|
||||
Amin = Bmin;
|
||||
if (Bmax < Amax)
|
||||
Amax = Bmax;
|
||||
if (Amax <= Amin)
|
||||
return SDL_FALSE;
|
||||
|
||||
/* Vertical intersection */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin > Amin)
|
||||
Amin = Bmin;
|
||||
if (Bmax < Amax)
|
||||
Amax = Bmax;
|
||||
if (Amax <= Amin)
|
||||
return SDL_FALSE;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
||||
const SDL_Rect * srcrect, const SDL_Rect * dstrect)
|
||||
|
|
|
@ -23,420 +23,8 @@
|
|||
#include "SDL_rect.h"
|
||||
#include "SDL_rect_c.h"
|
||||
|
||||
SDL_bool
|
||||
SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B)
|
||||
{
|
||||
int Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return SDL_FALSE;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return SDL_FALSE;
|
||||
} else if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
|
||||
return SDL_FALSE; /* Special cases for empty rects */
|
||||
}
|
||||
|
||||
/* Horizontal intersection */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
if (Amax <= Amin) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
/* Vertical intersection */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
if (Amax <= Amin) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
|
||||
{
|
||||
int Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return SDL_FALSE;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return SDL_FALSE;
|
||||
} else if (!result) {
|
||||
SDL_InvalidParamError("result");
|
||||
return SDL_FALSE;
|
||||
} else if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) { /* Special cases for empty rects */
|
||||
result->w = 0;
|
||||
result->h = 0;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Horizontal intersection */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->x = Amin;
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->w = Amax - Amin;
|
||||
|
||||
/* Vertical intersection */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->y = Amin;
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->h = Amax - Amin;
|
||||
|
||||
return !SDL_RectEmpty(result);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
|
||||
{
|
||||
int Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return;
|
||||
} else if (!result) {
|
||||
SDL_InvalidParamError("result");
|
||||
return;
|
||||
} else if (SDL_RectEmpty(A)) { /* Special cases for empty Rects */
|
||||
if (SDL_RectEmpty(B)) { /* A and B empty */
|
||||
SDL_zerop(result);
|
||||
} else { /* A empty, B not empty */
|
||||
*result = *B;
|
||||
}
|
||||
return;
|
||||
} else if (SDL_RectEmpty(B)) { /* A not empty, B empty */
|
||||
*result = *A;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Horizontal union */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin < Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->x = Amin;
|
||||
if (Bmax > Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->w = Amax - Amin;
|
||||
|
||||
/* Vertical union */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin < Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->y = Amin;
|
||||
if (Bmax > Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->h = Amax - Amin;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_EnclosePoints(const SDL_Point * points, int count, const SDL_Rect * clip,
|
||||
SDL_Rect * result)
|
||||
{
|
||||
int minx = 0;
|
||||
int miny = 0;
|
||||
int maxx = 0;
|
||||
int maxy = 0;
|
||||
int x, y, i;
|
||||
|
||||
if (!points) {
|
||||
SDL_InvalidParamError("points");
|
||||
return SDL_FALSE;
|
||||
} else if (count < 1) {
|
||||
SDL_InvalidParamError("count");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (clip) {
|
||||
SDL_bool added = SDL_FALSE;
|
||||
const int clip_minx = clip->x;
|
||||
const int clip_miny = clip->y;
|
||||
const int clip_maxx = clip->x+clip->w-1;
|
||||
const int clip_maxy = clip->y+clip->h-1;
|
||||
|
||||
/* Special case for empty rectangle */
|
||||
if (SDL_RectEmpty(clip)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
x = points[i].x;
|
||||
y = points[i].y;
|
||||
|
||||
if (x < clip_minx || x > clip_maxx ||
|
||||
y < clip_miny || y > clip_maxy) {
|
||||
continue;
|
||||
}
|
||||
if (!added) {
|
||||
/* Special case: if no result was requested, we are done */
|
||||
if (result == NULL) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* First point added */
|
||||
minx = maxx = x;
|
||||
miny = maxy = y;
|
||||
added = SDL_TRUE;
|
||||
continue;
|
||||
}
|
||||
if (x < minx) {
|
||||
minx = x;
|
||||
} else if (x > maxx) {
|
||||
maxx = x;
|
||||
}
|
||||
if (y < miny) {
|
||||
miny = y;
|
||||
} else if (y > maxy) {
|
||||
maxy = y;
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
} else {
|
||||
/* Special case: if no result was requested, we are done */
|
||||
if (result == NULL) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* No clipping, always add the first point */
|
||||
minx = maxx = points[0].x;
|
||||
miny = maxy = points[0].y;
|
||||
|
||||
for (i = 1; i < count; ++i) {
|
||||
x = points[i].x;
|
||||
y = points[i].y;
|
||||
|
||||
if (x < minx) {
|
||||
minx = x;
|
||||
} else if (x > maxx) {
|
||||
maxx = x;
|
||||
}
|
||||
if (y < miny) {
|
||||
miny = y;
|
||||
} else if (y > maxy) {
|
||||
maxy = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result->x = minx;
|
||||
result->y = miny;
|
||||
result->w = (maxx-minx)+1;
|
||||
result->h = (maxy-miny)+1;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Use the Cohen-Sutherland algorithm for line clipping */
|
||||
#define CODE_BOTTOM 1
|
||||
#define CODE_TOP 2
|
||||
#define CODE_LEFT 4
|
||||
#define CODE_RIGHT 8
|
||||
|
||||
static int
|
||||
ComputeOutCode(const SDL_Rect * rect, int x, int y)
|
||||
{
|
||||
int code = 0;
|
||||
if (y < rect->y) {
|
||||
code |= CODE_TOP;
|
||||
} else if (y >= rect->y + rect->h) {
|
||||
code |= CODE_BOTTOM;
|
||||
}
|
||||
if (x < rect->x) {
|
||||
code |= CODE_LEFT;
|
||||
} else if (x >= rect->x + rect->w) {
|
||||
code |= CODE_RIGHT;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IntersectRectAndLine(const SDL_Rect * rect, int *X1, int *Y1, int *X2,
|
||||
int *Y2)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int x1, y1;
|
||||
int x2, y2;
|
||||
int rectx1;
|
||||
int recty1;
|
||||
int rectx2;
|
||||
int recty2;
|
||||
int outcode1, outcode2;
|
||||
|
||||
if (!rect) {
|
||||
SDL_InvalidParamError("rect");
|
||||
return SDL_FALSE;
|
||||
} else if (!X1) {
|
||||
SDL_InvalidParamError("X1");
|
||||
return SDL_FALSE;
|
||||
} else if (!Y1) {
|
||||
SDL_InvalidParamError("Y1");
|
||||
return SDL_FALSE;
|
||||
} else if (!X2) {
|
||||
SDL_InvalidParamError("X2");
|
||||
return SDL_FALSE;
|
||||
} else if (!Y2) {
|
||||
SDL_InvalidParamError("Y2");
|
||||
return SDL_FALSE;
|
||||
} else if (SDL_RectEmpty(rect)) {
|
||||
return SDL_FALSE; /* Special case for empty rect */
|
||||
}
|
||||
|
||||
x1 = *X1;
|
||||
y1 = *Y1;
|
||||
x2 = *X2;
|
||||
y2 = *Y2;
|
||||
rectx1 = rect->x;
|
||||
recty1 = rect->y;
|
||||
rectx2 = rect->x + rect->w - 1;
|
||||
recty2 = rect->y + rect->h - 1;
|
||||
|
||||
/* Check to see if entire line is inside rect */
|
||||
if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
|
||||
y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Check to see if entire line is to one side of rect */
|
||||
if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
|
||||
(y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (y1 == y2) { /* Horizontal line, easy to clip */
|
||||
if (x1 < rectx1) {
|
||||
*X1 = rectx1;
|
||||
} else if (x1 > rectx2) {
|
||||
*X1 = rectx2;
|
||||
}
|
||||
if (x2 < rectx1) {
|
||||
*X2 = rectx1;
|
||||
} else if (x2 > rectx2) {
|
||||
*X2 = rectx2;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
if (x1 == x2) { /* Vertical line, easy to clip */
|
||||
if (y1 < recty1) {
|
||||
*Y1 = recty1;
|
||||
} else if (y1 > recty2) {
|
||||
*Y1 = recty2;
|
||||
}
|
||||
if (y2 < recty1) {
|
||||
*Y2 = recty1;
|
||||
} else if (y2 > recty2) {
|
||||
*Y2 = recty2;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* More complicated Cohen-Sutherland algorithm */
|
||||
outcode1 = ComputeOutCode(rect, x1, y1);
|
||||
outcode2 = ComputeOutCode(rect, x2, y2);
|
||||
while (outcode1 || outcode2) {
|
||||
if (outcode1 & outcode2) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (outcode1) {
|
||||
if (outcode1 & CODE_TOP) {
|
||||
y = recty1;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode1 & CODE_BOTTOM) {
|
||||
y = recty2;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode1 & CODE_LEFT) {
|
||||
x = rectx1;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
} else if (outcode1 & CODE_RIGHT) {
|
||||
x = rectx2;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
}
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
outcode1 = ComputeOutCode(rect, x, y);
|
||||
} else {
|
||||
if (outcode2 & CODE_TOP) {
|
||||
y = recty1;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode2 & CODE_BOTTOM) {
|
||||
y = recty2;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode2 & CODE_LEFT) {
|
||||
/* If this assertion ever fires, here's the static analysis that warned about it:
|
||||
http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */
|
||||
SDL_assert(x2 != x1); /* if equal: division by zero. */
|
||||
x = rectx1;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
} else if (outcode2 & CODE_RIGHT) {
|
||||
/* If this assertion ever fires, here's the static analysis that warned about it:
|
||||
http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */
|
||||
SDL_assert(x2 != x1); /* if equal: division by zero. */
|
||||
x = rectx2;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
}
|
||||
x2 = x;
|
||||
y2 = y;
|
||||
outcode2 = ComputeOutCode(rect, x, y);
|
||||
}
|
||||
}
|
||||
*X1 = x1;
|
||||
*Y1 = y1;
|
||||
*X2 = x2;
|
||||
*Y2 = y2;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* There's no float version of this at the moment, because it's not a public API
|
||||
and internally we only need the int version. */
|
||||
SDL_bool
|
||||
SDL_GetSpanEnclosingRect(int width, int height,
|
||||
int numrects, const SDL_Rect * rects, SDL_Rect *span)
|
||||
|
@ -492,4 +80,36 @@ SDL_GetSpanEnclosingRect(int width, int height,
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* For use with the Cohen-Sutherland algorithm for line clipping, in SDL_rect_impl.h */
|
||||
#define CODE_BOTTOM 1
|
||||
#define CODE_TOP 2
|
||||
#define CODE_LEFT 4
|
||||
#define CODE_RIGHT 8
|
||||
|
||||
/* Same code twice, for float and int versions... */
|
||||
#define RECTTYPE SDL_Rect
|
||||
#define POINTTYPE SDL_Point
|
||||
#define SCALARTYPE int
|
||||
#define COMPUTEOUTCODE ComputeOutCode
|
||||
#define SDL_HASINTERSECTION SDL_HasIntersection
|
||||
#define SDL_INTERSECTRECT SDL_IntersectRect
|
||||
#define SDL_RECTEMPTY SDL_RectEmpty
|
||||
#define SDL_UNIONRECT SDL_UnionRect
|
||||
#define SDL_ENCLOSEPOINTS SDL_EnclosePoints
|
||||
#define SDL_INTERSECTRECTANDLINE SDL_IntersectRectAndLine
|
||||
#include "SDL_rect_impl.h"
|
||||
|
||||
#define RECTTYPE SDL_FRect
|
||||
#define POINTTYPE SDL_FPoint
|
||||
#define SCALARTYPE float
|
||||
#define COMPUTEOUTCODE ComputeOutCodeF
|
||||
#define SDL_HASINTERSECTION SDL_HasIntersectionF
|
||||
#define SDL_INTERSECTRECT SDL_IntersectFRect
|
||||
#define SDL_RECTEMPTY SDL_FRectEmpty
|
||||
#define SDL_UNIONRECT SDL_UnionFRect
|
||||
#define SDL_ENCLOSEPOINTS SDL_EncloseFPoints
|
||||
#define SDL_INTERSECTRECTANDLINE SDL_IntersectFRectAndLine
|
||||
#include "SDL_rect_impl.h"
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* This file is #included twice to support int and float versions with the same code. */
|
||||
|
||||
SDL_bool
|
||||
SDL_HASINTERSECTION(const RECTTYPE * A, const RECTTYPE * B)
|
||||
{
|
||||
SCALARTYPE Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return SDL_FALSE;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return SDL_FALSE;
|
||||
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) {
|
||||
return SDL_FALSE; /* Special cases for empty rects */
|
||||
}
|
||||
|
||||
/* Horizontal intersection */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
if (Amax <= Amin) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
/* Vertical intersection */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
if (Amax <= Amin) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_INTERSECTRECT(const RECTTYPE * A, const RECTTYPE * B, RECTTYPE * result)
|
||||
{
|
||||
SCALARTYPE Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return SDL_FALSE;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return SDL_FALSE;
|
||||
} else if (!result) {
|
||||
SDL_InvalidParamError("result");
|
||||
return SDL_FALSE;
|
||||
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) { /* Special cases for empty rects */
|
||||
result->w = 0;
|
||||
result->h = 0;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Horizontal intersection */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->x = Amin;
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->w = Amax - Amin;
|
||||
|
||||
/* Vertical intersection */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin > Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->y = Amin;
|
||||
if (Bmax < Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->h = Amax - Amin;
|
||||
|
||||
return !SDL_RECTEMPTY(result);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_UNIONRECT(const RECTTYPE * A, const RECTTYPE * B, RECTTYPE * result)
|
||||
{
|
||||
SCALARTYPE Amin, Amax, Bmin, Bmax;
|
||||
|
||||
if (!A) {
|
||||
SDL_InvalidParamError("A");
|
||||
return;
|
||||
} else if (!B) {
|
||||
SDL_InvalidParamError("B");
|
||||
return;
|
||||
} else if (!result) {
|
||||
SDL_InvalidParamError("result");
|
||||
return;
|
||||
} else if (SDL_RECTEMPTY(A)) { /* Special cases for empty Rects */
|
||||
if (SDL_RECTEMPTY(B)) { /* A and B empty */
|
||||
SDL_zerop(result);
|
||||
} else { /* A empty, B not empty */
|
||||
*result = *B;
|
||||
}
|
||||
return;
|
||||
} else if (SDL_RECTEMPTY(B)) { /* A not empty, B empty */
|
||||
*result = *A;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Horizontal union */
|
||||
Amin = A->x;
|
||||
Amax = Amin + A->w;
|
||||
Bmin = B->x;
|
||||
Bmax = Bmin + B->w;
|
||||
if (Bmin < Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->x = Amin;
|
||||
if (Bmax > Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->w = Amax - Amin;
|
||||
|
||||
/* Vertical union */
|
||||
Amin = A->y;
|
||||
Amax = Amin + A->h;
|
||||
Bmin = B->y;
|
||||
Bmax = Bmin + B->h;
|
||||
if (Bmin < Amin) {
|
||||
Amin = Bmin;
|
||||
}
|
||||
result->y = Amin;
|
||||
if (Bmax > Amax) {
|
||||
Amax = Bmax;
|
||||
}
|
||||
result->h = Amax - Amin;
|
||||
}
|
||||
|
||||
SDL_bool SDL_ENCLOSEPOINTS(const POINTTYPE * points, int count, const RECTTYPE * clip,
|
||||
RECTTYPE * result)
|
||||
{
|
||||
SCALARTYPE minx = 0;
|
||||
SCALARTYPE miny = 0;
|
||||
SCALARTYPE maxx = 0;
|
||||
SCALARTYPE maxy = 0;
|
||||
SCALARTYPE x, y;
|
||||
int i;
|
||||
|
||||
if (!points) {
|
||||
SDL_InvalidParamError("points");
|
||||
return SDL_FALSE;
|
||||
} else if (count < 1) {
|
||||
SDL_InvalidParamError("count");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (clip) {
|
||||
SDL_bool added = SDL_FALSE;
|
||||
const SCALARTYPE clip_minx = clip->x;
|
||||
const SCALARTYPE clip_miny = clip->y;
|
||||
const SCALARTYPE clip_maxx = clip->x+clip->w-1;
|
||||
const SCALARTYPE clip_maxy = clip->y+clip->h-1;
|
||||
|
||||
/* Special case for empty rectangle */
|
||||
if (SDL_RECTEMPTY(clip)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
x = points[i].x;
|
||||
y = points[i].y;
|
||||
|
||||
if (x < clip_minx || x > clip_maxx ||
|
||||
y < clip_miny || y > clip_maxy) {
|
||||
continue;
|
||||
}
|
||||
if (!added) {
|
||||
/* Special case: if no result was requested, we are done */
|
||||
if (result == NULL) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* First point added */
|
||||
minx = maxx = x;
|
||||
miny = maxy = y;
|
||||
added = SDL_TRUE;
|
||||
continue;
|
||||
}
|
||||
if (x < minx) {
|
||||
minx = x;
|
||||
} else if (x > maxx) {
|
||||
maxx = x;
|
||||
}
|
||||
if (y < miny) {
|
||||
miny = y;
|
||||
} else if (y > maxy) {
|
||||
maxy = y;
|
||||
}
|
||||
}
|
||||
if (!added) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
} else {
|
||||
/* Special case: if no result was requested, we are done */
|
||||
if (result == NULL) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* No clipping, always add the first point */
|
||||
minx = maxx = points[0].x;
|
||||
miny = maxy = points[0].y;
|
||||
|
||||
for (i = 1; i < count; ++i) {
|
||||
x = points[i].x;
|
||||
y = points[i].y;
|
||||
|
||||
if (x < minx) {
|
||||
minx = x;
|
||||
} else if (x > maxx) {
|
||||
maxx = x;
|
||||
}
|
||||
if (y < miny) {
|
||||
miny = y;
|
||||
} else if (y > maxy) {
|
||||
maxy = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result->x = minx;
|
||||
result->y = miny;
|
||||
result->w = (maxx-minx)+1;
|
||||
result->h = (maxy-miny)+1;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Use the Cohen-Sutherland algorithm for line clipping */
|
||||
static int
|
||||
COMPUTEOUTCODE(const RECTTYPE * rect, SCALARTYPE x, SCALARTYPE y)
|
||||
{
|
||||
int code = 0;
|
||||
if (y < rect->y) {
|
||||
code |= CODE_TOP;
|
||||
} else if (y >= rect->y + rect->h) {
|
||||
code |= CODE_BOTTOM;
|
||||
}
|
||||
if (x < rect->x) {
|
||||
code |= CODE_LEFT;
|
||||
} else if (x >= rect->x + rect->w) {
|
||||
code |= CODE_RIGHT;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_INTERSECTRECTANDLINE(const RECTTYPE * rect, SCALARTYPE *X1, SCALARTYPE *Y1, SCALARTYPE *X2,
|
||||
SCALARTYPE *Y2)
|
||||
{
|
||||
SCALARTYPE x = 0;
|
||||
SCALARTYPE y = 0;
|
||||
SCALARTYPE x1, y1;
|
||||
SCALARTYPE x2, y2;
|
||||
SCALARTYPE rectx1;
|
||||
SCALARTYPE recty1;
|
||||
SCALARTYPE rectx2;
|
||||
SCALARTYPE recty2;
|
||||
int outcode1, outcode2;
|
||||
|
||||
if (!rect) {
|
||||
SDL_InvalidParamError("rect");
|
||||
return SDL_FALSE;
|
||||
} else if (!X1) {
|
||||
SDL_InvalidParamError("X1");
|
||||
return SDL_FALSE;
|
||||
} else if (!Y1) {
|
||||
SDL_InvalidParamError("Y1");
|
||||
return SDL_FALSE;
|
||||
} else if (!X2) {
|
||||
SDL_InvalidParamError("X2");
|
||||
return SDL_FALSE;
|
||||
} else if (!Y2) {
|
||||
SDL_InvalidParamError("Y2");
|
||||
return SDL_FALSE;
|
||||
} else if (SDL_RECTEMPTY(rect)) {
|
||||
return SDL_FALSE; /* Special case for empty rect */
|
||||
}
|
||||
|
||||
x1 = *X1;
|
||||
y1 = *Y1;
|
||||
x2 = *X2;
|
||||
y2 = *Y2;
|
||||
rectx1 = rect->x;
|
||||
recty1 = rect->y;
|
||||
rectx2 = rect->x + rect->w - 1;
|
||||
recty2 = rect->y + rect->h - 1;
|
||||
|
||||
/* Check to see if entire line is inside rect */
|
||||
if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
|
||||
y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Check to see if entire line is to one side of rect */
|
||||
if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
|
||||
(y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (y1 == y2) { /* Horizontal line, easy to clip */
|
||||
if (x1 < rectx1) {
|
||||
*X1 = rectx1;
|
||||
} else if (x1 > rectx2) {
|
||||
*X1 = rectx2;
|
||||
}
|
||||
if (x2 < rectx1) {
|
||||
*X2 = rectx1;
|
||||
} else if (x2 > rectx2) {
|
||||
*X2 = rectx2;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
if (x1 == x2) { /* Vertical line, easy to clip */
|
||||
if (y1 < recty1) {
|
||||
*Y1 = recty1;
|
||||
} else if (y1 > recty2) {
|
||||
*Y1 = recty2;
|
||||
}
|
||||
if (y2 < recty1) {
|
||||
*Y2 = recty1;
|
||||
} else if (y2 > recty2) {
|
||||
*Y2 = recty2;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* More complicated Cohen-Sutherland algorithm */
|
||||
outcode1 = COMPUTEOUTCODE(rect, x1, y1);
|
||||
outcode2 = COMPUTEOUTCODE(rect, x2, y2);
|
||||
while (outcode1 || outcode2) {
|
||||
if (outcode1 & outcode2) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (outcode1) {
|
||||
if (outcode1 & CODE_TOP) {
|
||||
y = recty1;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode1 & CODE_BOTTOM) {
|
||||
y = recty2;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode1 & CODE_LEFT) {
|
||||
x = rectx1;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
} else if (outcode1 & CODE_RIGHT) {
|
||||
x = rectx2;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
}
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
outcode1 = COMPUTEOUTCODE(rect, x, y);
|
||||
} else {
|
||||
if (outcode2 & CODE_TOP) {
|
||||
y = recty1;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode2 & CODE_BOTTOM) {
|
||||
y = recty2;
|
||||
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
|
||||
} else if (outcode2 & CODE_LEFT) {
|
||||
/* If this assertion ever fires, here's the static analysis that warned about it:
|
||||
http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */
|
||||
SDL_assert(x2 != x1); /* if equal: division by zero. */
|
||||
x = rectx1;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
} else if (outcode2 & CODE_RIGHT) {
|
||||
/* If this assertion ever fires, here's the static analysis that warned about it:
|
||||
http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */
|
||||
SDL_assert(x2 != x1); /* if equal: division by zero. */
|
||||
x = rectx2;
|
||||
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
|
||||
}
|
||||
x2 = x;
|
||||
y2 = y;
|
||||
outcode2 = COMPUTEOUTCODE(rect, x, y);
|
||||
}
|
||||
}
|
||||
*X1 = x1;
|
||||
*Y1 = y1;
|
||||
*X2 = x2;
|
||||
*Y2 = y2;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
#undef RECTTYPE
|
||||
#undef POINTTYPE
|
||||
#undef SCALARTYPE
|
||||
#undef COMPUTEOUTCODE
|
||||
#undef SDL_HASINTERSECTION
|
||||
#undef SDL_INTERSECTRECT
|
||||
#undef SDL_RECTEMPTY
|
||||
#undef SDL_UNIONRECT
|
||||
#undef SDL_ENCLOSEPOINTS
|
||||
#undef SDL_INTERSECTRECTANDLINE
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Reference in New Issue