cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_rect.c (12468B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      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#include "../SDL_internal.h"
     22
     23#include "SDL_rect.h"
     24#include "SDL_rect_c.h"
     25
     26
     27SDL_bool
     28SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B)
     29{
     30    int Amin, Amax, Bmin, Bmax;
     31
     32    if (!A) {
     33        SDL_InvalidParamError("A");
     34        return SDL_FALSE;
     35    }
     36
     37    if (!B) {
     38        SDL_InvalidParamError("B");
     39        return SDL_FALSE;
     40    }
     41
     42    /* Special cases for empty rects */
     43    if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
     44        return SDL_FALSE;
     45    }
     46
     47    /* Horizontal intersection */
     48    Amin = A->x;
     49    Amax = Amin + A->w;
     50    Bmin = B->x;
     51    Bmax = Bmin + B->w;
     52    if (Bmin > Amin)
     53        Amin = Bmin;
     54    if (Bmax < Amax)
     55        Amax = Bmax;
     56    if (Amax <= Amin)
     57        return SDL_FALSE;
     58
     59    /* Vertical intersection */
     60    Amin = A->y;
     61    Amax = Amin + A->h;
     62    Bmin = B->y;
     63    Bmax = Bmin + B->h;
     64    if (Bmin > Amin)
     65        Amin = Bmin;
     66    if (Bmax < Amax)
     67        Amax = Bmax;
     68    if (Amax <= Amin)
     69        return SDL_FALSE;
     70
     71    return SDL_TRUE;
     72}
     73
     74SDL_bool
     75SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
     76{
     77    int Amin, Amax, Bmin, Bmax;
     78
     79    if (!A) {
     80        SDL_InvalidParamError("A");
     81        return SDL_FALSE;
     82    }
     83
     84    if (!B) {
     85        SDL_InvalidParamError("B");
     86        return SDL_FALSE;
     87    }
     88
     89    if (!result) {
     90        SDL_InvalidParamError("result");
     91        return SDL_FALSE;
     92    }
     93
     94    /* Special cases for empty rects */
     95    if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
     96        result->w = 0;
     97        result->h = 0;
     98        return SDL_FALSE;
     99    }
    100
    101    /* Horizontal intersection */
    102    Amin = A->x;
    103    Amax = Amin + A->w;
    104    Bmin = B->x;
    105    Bmax = Bmin + B->w;
    106    if (Bmin > Amin)
    107        Amin = Bmin;
    108    result->x = Amin;
    109    if (Bmax < Amax)
    110        Amax = Bmax;
    111    result->w = Amax - Amin;
    112
    113    /* Vertical intersection */
    114    Amin = A->y;
    115    Amax = Amin + A->h;
    116    Bmin = B->y;
    117    Bmax = Bmin + B->h;
    118    if (Bmin > Amin)
    119        Amin = Bmin;
    120    result->y = Amin;
    121    if (Bmax < Amax)
    122        Amax = Bmax;
    123    result->h = Amax - Amin;
    124
    125    return !SDL_RectEmpty(result);
    126}
    127
    128void
    129SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
    130{
    131    int Amin, Amax, Bmin, Bmax;
    132
    133    if (!A) {
    134        SDL_InvalidParamError("A");
    135        return;
    136    }
    137
    138    if (!B) {
    139        SDL_InvalidParamError("B");
    140        return;
    141    }
    142
    143    if (!result) {
    144        SDL_InvalidParamError("result");
    145        return;
    146    }
    147
    148    /* Special cases for empty Rects */
    149    if (SDL_RectEmpty(A)) {
    150      if (SDL_RectEmpty(B)) {
    151       /* A and B empty */
    152       return;
    153      } else {
    154       /* A empty, B not empty */
    155       *result = *B;
    156       return;
    157      }
    158    } else {
    159      if (SDL_RectEmpty(B)) {
    160       /* A not empty, B empty */
    161       *result = *A;
    162       return;
    163      }
    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    result->x = Amin;
    174    if (Bmax > Amax)
    175        Amax = Bmax;
    176    result->w = Amax - Amin;
    177
    178    /* Vertical union */
    179    Amin = A->y;
    180    Amax = Amin + A->h;
    181    Bmin = B->y;
    182    Bmax = Bmin + B->h;
    183    if (Bmin < Amin)
    184        Amin = Bmin;
    185    result->y = Amin;
    186    if (Bmax > Amax)
    187        Amax = Bmax;
    188    result->h = Amax - Amin;
    189}
    190
    191SDL_bool
    192SDL_EnclosePoints(const SDL_Point * points, int count, const SDL_Rect * clip,
    193                  SDL_Rect * result)
    194{
    195    int minx = 0;
    196    int miny = 0;
    197    int maxx = 0;
    198    int maxy = 0;
    199    int x, y, i;
    200
    201    if (!points) {
    202        SDL_InvalidParamError("points");
    203        return SDL_FALSE;
    204    }
    205
    206    if (count < 1) {
    207        SDL_InvalidParamError("count");
    208        return SDL_FALSE;
    209    }
    210
    211    if (clip) {
    212        SDL_bool added = SDL_FALSE;
    213        const int clip_minx = clip->x;
    214        const int clip_miny = clip->y;
    215        const int clip_maxx = clip->x+clip->w-1;
    216        const int clip_maxy = clip->y+clip->h-1;
    217
    218        /* Special case for empty rectangle */
    219        if (SDL_RectEmpty(clip)) {
    220            return SDL_FALSE;
    221        }
    222
    223        for (i = 0; i < count; ++i) {
    224            x = points[i].x;
    225            y = points[i].y;
    226
    227            if (x < clip_minx || x > clip_maxx ||
    228                y < clip_miny || y > clip_maxy) {
    229                continue;
    230            }
    231            if (!added) {
    232                /* Special case: if no result was requested, we are done */
    233                if (result == NULL) {
    234                    return SDL_TRUE;
    235                }
    236
    237                /* First point added */
    238                minx = maxx = x;
    239                miny = maxy = y;
    240                added = SDL_TRUE;
    241                continue;
    242            }
    243            if (x < minx) {
    244                minx = x;
    245            } else if (x > maxx) {
    246                maxx = x;
    247            }
    248            if (y < miny) {
    249                miny = y;
    250            } else if (y > maxy) {
    251                maxy = y;
    252            }
    253        }
    254        if (!added) {
    255            return SDL_FALSE;
    256        }
    257    } else {
    258        /* Special case: if no result was requested, we are done */
    259        if (result == NULL) {
    260            return SDL_TRUE;
    261        }
    262
    263        /* No clipping, always add the first point */
    264        minx = maxx = points[0].x;
    265        miny = maxy = points[0].y;
    266
    267        for (i = 1; i < count; ++i) {
    268            x = points[i].x;
    269            y = points[i].y;
    270
    271            if (x < minx) {
    272                minx = x;
    273            } else if (x > maxx) {
    274                maxx = x;
    275            }
    276            if (y < miny) {
    277                miny = y;
    278            } else if (y > maxy) {
    279                maxy = y;
    280            }
    281        }
    282    }
    283
    284    if (result) {
    285        result->x = minx;
    286        result->y = miny;
    287        result->w = (maxx-minx)+1;
    288        result->h = (maxy-miny)+1;
    289    }
    290    return SDL_TRUE;
    291}
    292
    293/* Use the Cohen-Sutherland algorithm for line clipping */
    294#define CODE_BOTTOM 1
    295#define CODE_TOP    2
    296#define CODE_LEFT   4
    297#define CODE_RIGHT  8
    298
    299static int
    300ComputeOutCode(const SDL_Rect * rect, int x, int y)
    301{
    302    int code = 0;
    303    if (y < rect->y) {
    304        code |= CODE_TOP;
    305    } else if (y >= rect->y + rect->h) {
    306        code |= CODE_BOTTOM;
    307    }
    308    if (x < rect->x) {
    309        code |= CODE_LEFT;
    310    } else if (x >= rect->x + rect->w) {
    311        code |= CODE_RIGHT;
    312    }
    313    return code;
    314}
    315
    316SDL_bool
    317SDL_IntersectRectAndLine(const SDL_Rect * rect, int *X1, int *Y1, int *X2,
    318                         int *Y2)
    319{
    320    int x = 0;
    321    int y = 0;
    322    int x1, y1;
    323    int x2, y2;
    324    int rectx1;
    325    int recty1;
    326    int rectx2;
    327    int recty2;
    328    int outcode1, outcode2;
    329
    330    if (!rect) {
    331        SDL_InvalidParamError("rect");
    332        return SDL_FALSE;
    333    }
    334
    335    if (!X1) {
    336        SDL_InvalidParamError("X1");
    337        return SDL_FALSE;
    338    }
    339
    340    if (!Y1) {
    341        SDL_InvalidParamError("Y1");
    342        return SDL_FALSE;
    343    }
    344
    345    if (!X2) {
    346        SDL_InvalidParamError("X2");
    347        return SDL_FALSE;
    348    }
    349
    350    if (!Y2) {
    351        SDL_InvalidParamError("Y2");
    352        return SDL_FALSE;
    353    }
    354
    355    /* Special case for empty rect */
    356    if (SDL_RectEmpty(rect)) {
    357        return SDL_FALSE;
    358    }
    359
    360    x1 = *X1;
    361    y1 = *Y1;
    362    x2 = *X2;
    363    y2 = *Y2;
    364    rectx1 = rect->x;
    365    recty1 = rect->y;
    366    rectx2 = rect->x + rect->w - 1;
    367    recty2 = rect->y + rect->h - 1;
    368
    369    /* Check to see if entire line is inside rect */
    370    if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
    371        y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
    372        return SDL_TRUE;
    373    }
    374
    375    /* Check to see if entire line is to one side of rect */
    376    if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
    377        (y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
    378        return SDL_FALSE;
    379    }
    380
    381    if (y1 == y2) {
    382        /* Horizontal line, easy to clip */
    383        if (x1 < rectx1) {
    384            *X1 = rectx1;
    385        } else if (x1 > rectx2) {
    386            *X1 = rectx2;
    387        }
    388        if (x2 < rectx1) {
    389            *X2 = rectx1;
    390        } else if (x2 > rectx2) {
    391            *X2 = rectx2;
    392        }
    393        return SDL_TRUE;
    394    }
    395
    396    if (x1 == x2) {
    397        /* Vertical line, easy to clip */
    398        if (y1 < recty1) {
    399            *Y1 = recty1;
    400        } else if (y1 > recty2) {
    401            *Y1 = recty2;
    402        }
    403        if (y2 < recty1) {
    404            *Y2 = recty1;
    405        } else if (y2 > recty2) {
    406            *Y2 = recty2;
    407        }
    408        return SDL_TRUE;
    409    }
    410
    411    /* More complicated Cohen-Sutherland algorithm */
    412    outcode1 = ComputeOutCode(rect, x1, y1);
    413    outcode2 = ComputeOutCode(rect, x2, y2);
    414    while (outcode1 || outcode2) {
    415        if (outcode1 & outcode2) {
    416            return SDL_FALSE;
    417        }
    418
    419        if (outcode1) {
    420            if (outcode1 & CODE_TOP) {
    421                y = recty1;
    422                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
    423            } else if (outcode1 & CODE_BOTTOM) {
    424                y = recty2;
    425                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
    426            } else if (outcode1 & CODE_LEFT) {
    427                x = rectx1;
    428                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
    429            } else if (outcode1 & CODE_RIGHT) {
    430                x = rectx2;
    431                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
    432            }
    433            x1 = x;
    434            y1 = y;
    435            outcode1 = ComputeOutCode(rect, x, y);
    436        } else {
    437            if (outcode2 & CODE_TOP) {
    438                y = recty1;
    439                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
    440            } else if (outcode2 & CODE_BOTTOM) {
    441                y = recty2;
    442                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
    443            } else if (outcode2 & CODE_LEFT) {
    444                x = rectx1;
    445                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
    446            } else if (outcode2 & CODE_RIGHT) {
    447                x = rectx2;
    448                y = y1 + ((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 SDL_TRUE;
    460}
    461
    462SDL_bool
    463SDL_GetSpanEnclosingRect(int width, int height,
    464                         int numrects, const SDL_Rect * rects, SDL_Rect *span)
    465{
    466    int i;
    467    int span_y1, span_y2;
    468    int rect_y1, rect_y2;
    469
    470    if (width < 1) {
    471        SDL_InvalidParamError("width");
    472        return SDL_FALSE;
    473    }
    474
    475    if (height < 1) {
    476        SDL_InvalidParamError("height");
    477        return SDL_FALSE;
    478    }
    479
    480    if (!rects) {
    481        SDL_InvalidParamError("rects");
    482        return SDL_FALSE;
    483    }
    484
    485    if (!span) {
    486        SDL_InvalidParamError("span");
    487        return SDL_FALSE;
    488    }
    489
    490    if (numrects < 1) {
    491        SDL_InvalidParamError("numrects");
    492        return SDL_FALSE;
    493    }
    494
    495    /* Initialize to empty rect */
    496    span_y1 = height;
    497    span_y2 = 0;
    498
    499    for (i = 0; i < numrects; ++i) {
    500        rect_y1 = rects[i].y;
    501        rect_y2 = rect_y1 + rects[i].h;
    502
    503        /* Clip out of bounds rectangles, and expand span rect */
    504        if (rect_y1 < 0) {
    505            span_y1 = 0;
    506        } else if (rect_y1 < span_y1) {
    507            span_y1 = rect_y1;
    508        }
    509        if (rect_y2 > height) {
    510            span_y2 = height;
    511        } else if (rect_y2 > span_y2) {
    512            span_y2 = rect_y2;
    513        }
    514    }
    515    if (span_y2 > span_y1) {
    516        span->x = 0;
    517        span->y = span_y1;
    518        span->w = width;
    519        span->h = (span_y2 - span_y1);
    520        return SDL_TRUE;
    521    }
    522    return SDL_FALSE;
    523}
    524
    525/* vi: set ts=4 sw=4 expandtab: */