src/video/SDL_rect.c
author Sam Lantinga
Tue, 23 Dec 2008 02:23:18 +0000
changeset 2909 3da0bb421d83
parent 2859 99210400e8b9
child 2920 cdb01906cb7e
permissions -rw-r--r--
Added line clipping
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_video.h"
    25 #include "SDL_rect_c.h"
    26 
    27 SDL_bool
    28 SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B)
    29 {
    30     int Amin, Amax, Bmin, Bmax;
    31 
    32     /* Horizontal intersection */
    33     Amin = A->x;
    34     Amax = Amin + A->w;
    35     Bmin = B->x;
    36     Bmax = Bmin + B->w;
    37     if (Bmin > Amin)
    38         Amin = Bmin;
    39     if (Bmax < Amax)
    40         Amax = Bmax;
    41     if (Amax <= Amin)
    42         return SDL_FALSE;
    43 
    44     /* Vertical intersection */
    45     Amin = A->y;
    46     Amax = Amin + A->h;
    47     Bmin = B->y;
    48     Bmax = Bmin + B->h;
    49     if (Bmin > Amin)
    50         Amin = Bmin;
    51     if (Bmax < Amax)
    52         Amax = Bmax;
    53     if (Amax <= Amin)
    54         return SDL_FALSE;
    55 
    56     return SDL_TRUE;
    57 }
    58 
    59 SDL_bool
    60 SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
    61 {
    62     int Amin, Amax, Bmin, Bmax;
    63 
    64     /* Horizontal intersection */
    65     Amin = A->x;
    66     Amax = Amin + A->w;
    67     Bmin = B->x;
    68     Bmax = Bmin + B->w;
    69     if (Bmin > Amin)
    70         Amin = Bmin;
    71     result->x = Amin;
    72     if (Bmax < Amax)
    73         Amax = Bmax;
    74     result->w = Amax - Amin;
    75 
    76     /* Vertical intersection */
    77     Amin = A->y;
    78     Amax = Amin + A->h;
    79     Bmin = B->y;
    80     Bmax = Bmin + B->h;
    81     if (Bmin > Amin)
    82         Amin = Bmin;
    83     result->y = Amin;
    84     if (Bmax < Amax)
    85         Amax = Bmax;
    86     result->h = Amax - Amin;
    87 
    88     return !SDL_RectEmpty(result);
    89 }
    90 
    91 void
    92 SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
    93 {
    94     int Amin, Amax, Bmin, Bmax;
    95 
    96     /* Horizontal union */
    97     Amin = A->x;
    98     Amax = Amin + A->w;
    99     Bmin = B->x;
   100     Bmax = Bmin + B->w;
   101     if (Bmin < Amin)
   102         Amin = Bmin;
   103     result->x = Amin;
   104     if (Bmax > Amax)
   105         Amax = Bmax;
   106     result->w = Amax - Amin;
   107 
   108     /* Vertical intersection */
   109     Amin = A->y;
   110     Amax = Amin + A->h;
   111     Bmin = B->y;
   112     Bmax = Bmin + B->h;
   113     if (Bmin < Amin)
   114         Amin = Bmin;
   115     result->y = Amin;
   116     if (Bmax > Amax)
   117         Amax = Bmax;
   118     result->h = Amax - Amin;
   119 }
   120 
   121 SDL_bool
   122 SDL_IntersectRectAndLine(const SDL_Rect *rect, int *X1, int *Y1, int *X2, int *Y2)
   123 {
   124     int x1, y1;
   125     int x2, y2;
   126     int rectx1;
   127     int recty1;
   128     int rectx2;
   129     int recty2;
   130 
   131     if (!rect || !X1 || !Y1 || !X2 || !Y2) {
   132         SDL_FALSE;
   133     }
   134 
   135     x1 = *X1;
   136     y1 = *Y1;
   137     x2 = *X2;
   138     y2 = *Y2;
   139     rectx1 = rect->x;
   140     recty1 = rect->y;
   141     rectx2 = rect->x + rect->w - 1;
   142     recty2 = rect->y + rect->h - 1;
   143 
   144     /* Check to see if entire line is inside rect */
   145     if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
   146         y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
   147         return SDL_TRUE;
   148     }
   149 
   150     /* Check to see if entire line is outside rect */
   151     if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
   152         (y1 < recty1 && y2 < recty2) || (y1 > recty2 && y2 > recty2)) {
   153         return SDL_FALSE;
   154     }
   155 
   156     if (y1 = y2) {
   157         /* Horizontal line, easy to clip */
   158         if (x1 < rectx1) {
   159             *X1 = rectx1;
   160         } else if (x1 > rectx2) {
   161             *X1 = rectx2;
   162         }
   163         if (x2 < rectx1) {
   164             *X2 = rectx1;
   165         } else if (x2 > rectx2) {
   166             *X2 = rectx2;
   167         }
   168         return SDL_TRUE;
   169     }
   170 
   171     if (x1 == x2) {
   172         /* Vertical line, easy to clip */
   173         if (y1 < recty1) {
   174             *Y1 = recty1;
   175         } else if (y1 > recty2) {
   176             *Y1 = recty2;
   177         }
   178         if (y2 < recty1) {
   179             *Y2 = recty1;
   180         } else if (y2 > recty2) {
   181             *Y2 = recty2;
   182         }
   183         return SDL_TRUE;
   184     }
   185 
   186     /* FIXME: need code to clip diagonal line to rect */
   187     return SDL_FALSE;
   188 }
   189 
   190 void
   191 SDL_AddDirtyRect(SDL_DirtyRectList * list, const SDL_Rect * rect)
   192 {
   193     SDL_DirtyRect *dirty;
   194 
   195     /* FIXME: At what point is this optimization too expensive? */
   196     for (dirty = list->list; dirty; dirty = dirty->next) {
   197         if (SDL_HasIntersection(&dirty->rect, rect)) {
   198             SDL_UnionRect(&dirty->rect, rect, &dirty->rect);
   199             return;
   200         }
   201     }
   202 
   203     if (list->free) {
   204         dirty = list->free;
   205         list->free = dirty->next;
   206     } else {
   207         dirty = (SDL_DirtyRect *) SDL_malloc(sizeof(*dirty));
   208         if (!dirty) {
   209             return;
   210         }
   211     }
   212     dirty->rect = *rect;
   213     dirty->next = list->list;
   214     list->list = dirty;
   215 }
   216 
   217 void
   218 SDL_ClearDirtyRects(SDL_DirtyRectList * list)
   219 {
   220     SDL_DirtyRect *prev, *curr;
   221 
   222     /* Skip to the end of the free list */
   223     prev = NULL;
   224     for (curr = list->free; curr; curr = curr->next) {
   225         prev = curr;
   226     }
   227 
   228     /* Add the list entries to the end */
   229     if (prev) {
   230         prev->next = list->list;
   231     } else {
   232         list->free = list->list;
   233     }
   234     list->list = NULL;
   235 }
   236 
   237 void
   238 SDL_FreeDirtyRects(SDL_DirtyRectList * list)
   239 {
   240     while (list->list) {
   241         SDL_DirtyRect *elem = list->list;
   242         list->list = elem->next;
   243         SDL_free(elem);
   244     }
   245     while (list->free) {
   246         SDL_DirtyRect *elem = list->free;
   247         list->free = elem->next;
   248         SDL_free(elem);
   249     }
   250 }
   251 
   252 /* vi: set ts=4 sw=4 expandtab: */