src/render/software/SDL_drawline.c
author Sam Lantinga
Thu, 03 Feb 2011 15:49:37 -0800
changeset 5166 4d39eeaad00b
parent 5163 d72793305335
child 5226 710d00cb3a6a
permissions -rwxr-xr-x
Added a way to get a framebuffer interface for a window, and also a way to create a software renderer for an arbitrary surface.
The software renderer has been re-routed to use the framebuffer interface, which makes it possible to have software rendering available even on simple ports.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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_draw.h"
    25 #include "SDL_drawline.h"
    26 #include "SDL_drawpoint.h"
    27 
    28 
    29 static void
    30 SDL_DrawLine1(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color,
    31               SDL_bool draw_end)
    32 {
    33     if (y1 == y2) {
    34         //HLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
    35         int length;
    36         int pitch = (dst->pitch / dst->format->BytesPerPixel);
    37         Uint8 *pixel;
    38         if (x1 <= x2) {
    39             pixel = (Uint8 *)dst->pixels + y1 * pitch + x1;
    40             length = draw_end ? (x2-x1+1) : (x2-x1);
    41         } else {
    42             pixel = (Uint8 *)dst->pixels + y1 * pitch + x2;
    43             if (!draw_end) {
    44                 ++pixel;
    45             }
    46             length = draw_end ? (x1-x2+1) : (x1-x2);
    47         }
    48         SDL_memset(pixel, color, length);
    49     } else if (x1 == x2) {
    50         VLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
    51     } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
    52         DLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
    53     } else {
    54         BLINE(x1, y1, x2, y2, DRAW_FASTSETPIXELXY1, draw_end);
    55     }
    56 }
    57 
    58 static void
    59 SDL_DrawLine2(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color,
    60               SDL_bool draw_end)
    61 {
    62     if (y1 == y2) {
    63         HLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
    64     } else if (x1 == x2) {
    65         VLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
    66     } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
    67         DLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
    68     } else {
    69         Uint8 _r, _g, _b, _a;
    70         const SDL_PixelFormat * fmt = dst->format;
    71         SDL_GetRGBA(color, fmt, &_r, &_g, &_b, &_a);
    72         if (fmt->Rmask == 0x7C00) {
    73             AALINE(x1, y1, x2, y2,
    74                    DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB555,
    75                    draw_end);
    76         } else if (fmt->Rmask == 0xF800) {
    77             AALINE(x1, y1, x2, y2,
    78                    DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB565,
    79                    draw_end);
    80         } else {
    81             AALINE(x1, y1, x2, y2,
    82                    DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY2_BLEND_RGB,
    83                    draw_end);
    84         }
    85     }
    86 }
    87 
    88 static void
    89 SDL_DrawLine4(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color,
    90               SDL_bool draw_end)
    91 {
    92     if (y1 == y2) {
    93         HLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
    94     } else if (x1 == x2) {
    95         VLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
    96     } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
    97         DLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
    98     } else {
    99         Uint8 _r, _g, _b, _a;
   100         const SDL_PixelFormat * fmt = dst->format;
   101         SDL_GetRGBA(color, fmt, &_r, &_g, &_b, &_a);
   102         if (fmt->Rmask == 0x00FF0000) {
   103             if (!fmt->Amask) {
   104                 AALINE(x1, y1, x2, y2,
   105                        DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_RGB888,
   106                        draw_end);
   107             } else {
   108                 AALINE(x1, y1, x2, y2,
   109                        DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_ARGB8888,
   110                        draw_end);
   111             }
   112         } else {
   113             AALINE(x1, y1, x2, y2,
   114                    DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY4_BLEND_RGB,
   115                    draw_end);
   116         }
   117     }
   118 }
   119 
   120 typedef void (*DrawLineFunc) (SDL_Surface * dst,
   121                               int x1, int y1, int x2, int y2,
   122                               Uint32 color, SDL_bool draw_end);
   123 
   124 static DrawLineFunc
   125 SDL_CalculateDrawLineFunc(const SDL_PixelFormat * fmt)
   126 {
   127     switch (fmt->BytesPerPixel) {
   128     case 1:
   129         if (fmt->BitsPerPixel < 8) {
   130             break;
   131         }
   132         return SDL_DrawLine1;
   133     case 2:
   134         return SDL_DrawLine2;
   135     case 4:
   136         return SDL_DrawLine4;
   137     }
   138     return NULL;
   139 }
   140 
   141 int
   142 SDL_DrawLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color)
   143 {
   144     DrawLineFunc func;
   145 
   146     if (!dst) {
   147         SDL_SetError("SDL_DrawLine(): Passed NULL destination surface");
   148         return -1;
   149     }
   150 
   151     func = SDL_CalculateDrawLineFunc(dst->format);
   152     if (!func) {
   153         SDL_SetError("SDL_DrawLine(): Unsupported surface format");
   154         return -1;
   155     }
   156 
   157     /* Perform clipping */
   158     /* FIXME: We don't actually want to clip, as it may change line slope */
   159     if (!SDL_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
   160         return 0;
   161     }
   162 
   163     func(dst, x1, y1, x2, y2, color, SDL_TRUE);
   164     return 0;
   165 }
   166 
   167 int
   168 SDL_DrawLines(SDL_Surface * dst, const SDL_Point * points, int count,
   169               Uint32 color)
   170 {
   171     int i;
   172     int x1, y1;
   173     int x2, y2;
   174     SDL_bool draw_end;
   175     DrawLineFunc func;
   176 
   177     if (!dst) {
   178         SDL_SetError("SDL_DrawLines(): Passed NULL destination surface");
   179         return -1;
   180     }
   181 
   182     func = SDL_CalculateDrawLineFunc(dst->format);
   183     if (!func) {
   184         SDL_SetError("SDL_DrawLines(): Unsupported surface format");
   185         return -1;
   186     }
   187 
   188     for (i = 1; i < count; ++i) {
   189         x1 = points[i-1].x;
   190         y1 = points[i-1].y;
   191         x2 = points[i].x;
   192         y2 = points[i].y;
   193 
   194         /* Perform clipping */
   195         /* FIXME: We don't actually want to clip, as it may change line slope */
   196         if (!SDL_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
   197             continue;
   198         }
   199 
   200         /* Draw the end if it was clipped */
   201         draw_end = (x2 != points[i].x || y2 != points[i].y);
   202 
   203         func(dst, x1, y1, x2, y2, color, draw_end);
   204     }
   205     if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
   206         SDL_DrawPoint(dst, points[count-1].x, points[count-1].y, color);
   207     }
   208     return 0;
   209 }
   210 
   211 /* vi: set ts=4 sw=4 expandtab: */