diff src/video/SDL_blendline.c @ 3596:f638ded38b8a

Added SDL_RenderClear() as a fast method of clearing the screen to the drawing color. Renamed SDL_RenderPoint() and SDL_RenderLine() to SDL_RenderDrawPoint() and SDL_RenderDrawLine(). Added API for rectangle drawing (as opposed to filling) Added placeholder API functions for circles and ellipses ... I'm not sure whether these will stay. Optimized software line drawing quite a bit. Added support for Wu's anti-aliased line drawing, currently disabled by default.
author Sam Lantinga <slouken@libsdl.org>
date Wed, 23 Dec 2009 01:55:00 +0000
parents c8bed77b0386
children f7b03b6838cb
line wrap: on
line diff
--- a/src/video/SDL_blendline.c	Fri Dec 18 08:19:18 2009 +0000
+++ b/src/video/SDL_blendline.c	Wed Dec 23 01:55:00 2009 +0000
@@ -23,241 +23,713 @@
 
 #include "SDL_draw.h"
 
-static int
-SDL_BlendLine_RGB555(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                     int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
-                     SDL_bool draw_end)
+
+static void
+SDL_BlendLine_RGB2(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                   int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
+                   SDL_bool draw_end)
 {
-    unsigned inva = 0xff - a;
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
+
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
+    }
+    inva = (a ^ 0xff);
 
-    switch (blendMode) {
-    case SDL_BLENDMODE_BLEND:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_BLEND_RGB555, draw_end);
-        break;
-    case SDL_BLENDMODE_ADD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_ADD_RGB555, draw_end);
-        break;
-    case SDL_BLENDMODE_MOD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_MOD_RGB555, draw_end);
-        break;
-    default:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_RGB555, draw_end);
-        break;
+    if (y1 == y2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
+            break;
+        default:
+            HLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
+            break;
+        }
+    } else if (x1 == x2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
+            break;
+        default:
+            VLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
+            break;
+        }
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
+            break;
+        default:
+            DLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
+            break;
+        }
+    } else {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY2_BLEND_RGB, DRAW_SETPIXELXY2_BLEND_RGB,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY2_ADD_RGB, DRAW_SETPIXELXY2_ADD_RGB,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY2_MOD_RGB, DRAW_SETPIXELXY2_MOD_RGB,
+                   draw_end);
+            break;
+        default:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY2_RGB, DRAW_SETPIXELXY2_BLEND_RGB,
+                   draw_end);
+            break;
+        }
     }
-    return 0;
 }
 
-static int
-SDL_BlendLine_RGB565(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                     int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
-                     SDL_bool draw_end)
-{
-    unsigned inva = 0xff - a;
-
-    switch (blendMode) {
-    case SDL_BLENDMODE_BLEND:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_BLEND_RGB565, draw_end);
-        break;
-    case SDL_BLENDMODE_ADD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_ADD_RGB565, draw_end);
-        break;
-    case SDL_BLENDMODE_MOD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_MOD_RGB565, draw_end);
-        break;
-    default:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_RGB565, draw_end);
-        break;
-    }
-    return 0;
-}
-
-static int
-SDL_BlendLine_RGB888(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                     int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
+static void
+SDL_BlendLine_RGB555(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                     int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
                      SDL_bool draw_end)
 {
-    unsigned inva = 0xff - a;
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
 
-    switch (blendMode) {
-    case SDL_BLENDMODE_BLEND:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_BLEND_RGB888, draw_end);
-        break;
-    case SDL_BLENDMODE_ADD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_ADD_RGB888, draw_end);
-        break;
-    case SDL_BLENDMODE_MOD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_MOD_RGB888, draw_end);
-        break;
-    default:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_RGB888, draw_end);
-        break;
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
     }
-    return 0;
-}
+    inva = (a ^ 0xff);
 
-static int
-SDL_BlendLine_ARGB8888(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                       int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
-                       SDL_bool draw_end)
-{
-    unsigned inva = 0xff - a;
-
-    switch (blendMode) {
-    case SDL_BLENDMODE_BLEND:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_BLEND_ARGB8888, draw_end);
-        break;
-    case SDL_BLENDMODE_ADD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_ADD_ARGB8888, draw_end);
-        break;
-    case SDL_BLENDMODE_MOD:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_MOD_ARGB8888, draw_end);
-        break;
-    default:
-        DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY_ARGB8888, draw_end);
-        break;
+    if (y1 == y2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
+            break;
+        default:
+            HLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
+            break;
+        }
+    } else if (x1 == x2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
+            break;
+        default:
+            VLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
+            break;
+        }
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
+            break;
+        default:
+            DLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
+            break;
+        }
+    } else {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_BLEND_RGB555, DRAW_SETPIXELXY_BLEND_RGB555,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_ADD_RGB555, DRAW_SETPIXELXY_ADD_RGB555,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_MOD_RGB555, DRAW_SETPIXELXY_MOD_RGB555,
+                   draw_end);
+            break;
+        default:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_RGB555, DRAW_SETPIXELXY_BLEND_RGB555,
+                   draw_end);
+            break;
+        }
     }
-    return 0;
 }
 
-static int
-SDL_BlendLine_RGB(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                  int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
-                  SDL_bool draw_end)
+static void
+SDL_BlendLine_RGB565(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                     int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
+                     SDL_bool draw_end)
 {
-    SDL_PixelFormat *fmt = dst->format;
-    unsigned inva = 0xff - a;
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
 
-    switch (fmt->BytesPerPixel) {
-    case 2:
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
+    }
+    inva = (a ^ 0xff);
+
+    if (y1 == y2) {
         switch (blendMode) {
         case SDL_BLENDMODE_BLEND:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY2_BLEND_RGB, draw_end);
+            HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
             break;
         case SDL_BLENDMODE_ADD:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY2_ADD_RGB, draw_end);
+            HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
             break;
         case SDL_BLENDMODE_MOD:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY2_MOD_RGB, draw_end);
+            HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
             break;
         default:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY2_RGB, draw_end);
+            HLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
             break;
         }
-        return 0;
-    case 4:
+    } else if (x1 == x2) {
         switch (blendMode) {
         case SDL_BLENDMODE_BLEND:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_BLEND_RGB, draw_end);
+            VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
+            break;
+        default:
+            VLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
+            break;
+        }
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
             break;
         case SDL_BLENDMODE_ADD:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_ADD_RGB, draw_end);
+            DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
             break;
         case SDL_BLENDMODE_MOD:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_MOD_RGB, draw_end);
+            DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
             break;
         default:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_RGB, draw_end);
+            DLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
             break;
         }
-        return 0;
-    default:
-        SDL_Unsupported();
-        return -1;
+    } else {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_BLEND_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_ADD_RGB565, DRAW_SETPIXELXY_ADD_RGB565,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_MOD_RGB565, DRAW_SETPIXELXY_MOD_RGB565,
+                   draw_end);
+            break;
+        default:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
+                   draw_end);
+            break;
+        }
     }
 }
 
-static int
-SDL_BlendLine_RGBA(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                   int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
+static void
+SDL_BlendLine_RGB4(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                   int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
                    SDL_bool draw_end)
 {
-    SDL_PixelFormat *fmt = dst->format;
-    unsigned inva = 0xff - a;
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
+
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
+    }
+    inva = (a ^ 0xff);
 
-    switch (fmt->BytesPerPixel) {
-    case 4:
+    if (y1 == y2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            HLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            HLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
+            break;
+        default:
+            HLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
+            break;
+        }
+    } else if (x1 == x2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
+            break;
+        default:
+            VLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
+            break;
+        }
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            DLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            DLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
+            break;
+        default:
+            DLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
+            break;
+        }
+    } else {
         switch (blendMode) {
         case SDL_BLENDMODE_BLEND:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_BLEND_RGBA, draw_end);
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_BLEND_RGB, DRAW_SETPIXELXY4_BLEND_RGB,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_ADD_RGB, DRAW_SETPIXELXY4_ADD_RGB,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_MOD_RGB, DRAW_SETPIXELXY4_MOD_RGB,
+                   draw_end);
+            break;
+        default:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_RGB, DRAW_SETPIXELXY4_BLEND_RGB,
+                   draw_end);
+            break;
+        }
+    }
+}
+
+static void
+SDL_BlendLine_RGBA4(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                    int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
+                    SDL_bool draw_end)
+{
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
+
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
+    }
+    inva = (a ^ 0xff);
+
+    if (y1 == y2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            HLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            HLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
+            break;
+        default:
+            HLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
+            break;
+        }
+    } else if (x1 == x2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
+            break;
+        default:
+            VLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
+            break;
+        }
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            DLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            DLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
+            break;
+        default:
+            DLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
+            break;
+        }
+    } else {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_BLEND_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA,
+                   draw_end);
             break;
         case SDL_BLENDMODE_ADD:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_ADD_RGBA, draw_end);
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_ADD_RGBA, DRAW_SETPIXELXY4_ADD_RGBA,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_MOD_RGBA, DRAW_SETPIXELXY4_MOD_RGBA,
+                   draw_end);
+            break;
+        default:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY4_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA,
+                   draw_end);
+            break;
+        }
+    }
+}
+
+static void
+SDL_BlendLine_RGB888(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                     int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
+                     SDL_bool draw_end)
+{
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
+
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
+    }
+    inva = (a ^ 0xff);
+
+    if (y1 == y2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB888, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            HLINE(Uint32, DRAW_SETPIXEL_ADD_RGB888, draw_end);
             break;
         case SDL_BLENDMODE_MOD:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_MOD_RGBA, draw_end);
+            HLINE(Uint32, DRAW_SETPIXEL_MOD_RGB888, draw_end);
+            break;
+        default:
+            HLINE(Uint32, DRAW_SETPIXEL_RGB888, draw_end);
+            break;
+        }
+    } else if (x1 == x2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB888, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint32, DRAW_SETPIXEL_ADD_RGB888, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint32, DRAW_SETPIXEL_MOD_RGB888, draw_end);
+            break;
+        default:
+            VLINE(Uint32, DRAW_SETPIXEL_RGB888, draw_end);
+            break;
+        }
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB888, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            DLINE(Uint32, DRAW_SETPIXEL_ADD_RGB888, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            DLINE(Uint32, DRAW_SETPIXEL_MOD_RGB888, draw_end);
+            break;
+        default:
+            DLINE(Uint32, DRAW_SETPIXEL_RGB888, draw_end);
+            break;
+        }
+    } else {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_BLEND_RGB888, DRAW_SETPIXELXY_BLEND_RGB888,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_ADD_RGB888, DRAW_SETPIXELXY_ADD_RGB888,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_MOD_RGB888, DRAW_SETPIXELXY_MOD_RGB888,
+                   draw_end);
             break;
         default:
-            DRAWLINE(x1, y1, x2, y2, DRAW_SETPIXELXY4_RGBA, draw_end);
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_RGB888, DRAW_SETPIXELXY_BLEND_RGB888,
+                   draw_end);
+            break;
+        }
+    }
+}
+
+static void
+SDL_BlendLine_ARGB8888(SDL_Surface * dst, int x1, int y1, int x2, int y2,
+                       int blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
+                       SDL_bool draw_end)
+{
+    const SDL_PixelFormat *fmt = dst->format;
+    unsigned r, g, b, a, inva;
+
+    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
+        r = DRAW_MUL(_r, _a);
+        g = DRAW_MUL(_g, _a);
+        b = DRAW_MUL(_b, _a);
+        a = _a;
+    } else {
+        r = _r;
+        g = _g;
+        b = _b;
+        a = _a;
+    }
+    inva = (a ^ 0xff);
+
+    if (y1 == y2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            HLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            HLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            HLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
+            break;
+        default:
+            HLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
+            break;
+        }
+    } else if (x1 == x2) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            VLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            VLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            VLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
+            break;
+        default:
+            VLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
             break;
         }
-        return 0;
-    default:
-        SDL_Unsupported();
-        return -1;
+    } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            DLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            DLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            DLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
+            break;
+        default:
+            DLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
+            break;
+        }
+    } else {
+        switch (blendMode) {
+        case SDL_BLENDMODE_BLEND:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_BLEND_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_ADD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_ADD_ARGB8888, DRAW_SETPIXELXY_ADD_ARGB8888,
+                   draw_end);
+            break;
+        case SDL_BLENDMODE_MOD:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_MOD_ARGB8888, DRAW_SETPIXELXY_MOD_ARGB8888,
+                   draw_end);
+            break;
+        default:
+            AALINE(x1, y1, x2, y2,
+                   DRAW_SETPIXELXY_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
+                   draw_end);
+            break;
+        }
     }
 }
 
+typedef void (*BlendLineFunc) (SDL_Surface * dst,
+                               int x1, int y1, int x2, int y2,
+                               int blendMode,
+                               Uint8 r, Uint8 g, Uint8 b, Uint8 a,
+                               SDL_bool draw_end);
+
+static BlendLineFunc
+SDL_CalculateBlendLineFunc(const SDL_PixelFormat * fmt)
+{
+    switch (fmt->BytesPerPixel) {
+    case 2:
+        if (fmt->Rmask == 0x7C00) {
+            return SDL_BlendLine_RGB555;
+        } else if (fmt->Rmask == 0xF800) {
+            return SDL_BlendLine_RGB565;
+        } else {
+            return SDL_BlendLine_RGB2;
+        }
+        break;
+    case 4:
+        if (fmt->Rmask == 0x00FF0000) {
+            if (fmt->Amask) {
+                return SDL_BlendLine_ARGB8888;
+            } else {
+                return SDL_BlendLine_RGB888;
+            }
+        } else {
+            if (fmt->Amask) {
+                return SDL_BlendLine_RGBA4;
+            } else {
+                return SDL_BlendLine_RGB4;
+            }
+        }
+    }
+    return NULL;
+}
+
 int
 SDL_BlendLine(SDL_Surface * dst, int x1, int y1, int x2, int y2,
               int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
 {
-    /* This function doesn't work on surfaces < 8 bpp */
-    if (dst->format->BitsPerPixel < 8) {
+    BlendLineFunc func;
+
+    if (!dst) {
+        SDL_SetError("SDL_BlendLine(): Passed NULL destination surface");
+        return -1;
+    }
+
+    func = SDL_CalculateBlendLineFunc(dst->format);
+    if (!func) {
         SDL_SetError("SDL_BlendLine(): Unsupported surface format");
-        return (-1);
+        return -1;
     }
 
     /* Perform clipping */
+    /* FIXME: We don't actually want to clip, as it may change line slope */
     if (!SDL_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
-        return (0);
-    }
-
-
-    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
-        r = DRAW_MUL(r, a);
-        g = DRAW_MUL(g, a);
-        b = DRAW_MUL(b, a);
+        return 0;
     }
 
-    switch (dst->format->BitsPerPixel) {
-    case 15:
-        switch (dst->format->Rmask) {
-        case 0x7C00:
-            return SDL_BlendLine_RGB555(dst, x1, y1, x2, y2, blendMode, r, g,
-                                        b, a, SDL_TRUE);
-        }
-        break;
-    case 16:
-        switch (dst->format->Rmask) {
-        case 0xF800:
-            return SDL_BlendLine_RGB565(dst, x1, y1, x2, y2, blendMode, r, g,
-                                        b, a, SDL_TRUE);
-        }
-        break;
-    case 32:
-        switch (dst->format->Rmask) {
-        case 0x00FF0000:
-            if (!dst->format->Amask) {
-                return SDL_BlendLine_RGB888(dst, x1, y1, x2, y2, blendMode, r,
-                                            g, b, a, SDL_TRUE);
-            } else {
-                return SDL_BlendLine_ARGB8888(dst, x1, y1, x2, y2, blendMode,
-                                              r, g, b, a, SDL_TRUE);
-            }
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-
-    if (!dst->format->Amask) {
-        return SDL_BlendLine_RGB(dst, x1, y1, x2, y2, blendMode,
-                                 r, g, b, a, SDL_TRUE);
-    } else {
-        return SDL_BlendLine_RGBA(dst, x1, y1, x2, y2, blendMode,
-                                  r, g, b, a, SDL_TRUE);
-    }
+    func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, SDL_TRUE);
+    return 0;
 }
 
 int
@@ -267,62 +739,18 @@
     int i;
     int x1, y1;
     int x2, y2;
-    int (*func)(SDL_Surface * dst, int x1, int y1, int x2, int y2,
-                int blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a,
-                SDL_bool draw_end) = NULL;
-    int status = 0;
+    SDL_bool draw_end;
+    BlendLineFunc func;
 
     if (!dst) {
-        SDL_SetError("Passed NULL destination surface");
-        return -1;
-    }
-
-    /* This function doesn't work on surfaces < 8 bpp */
-    if (dst->format->BitsPerPixel < 8) {
-        SDL_SetError("SDL_BlendLines(): Unsupported surface format");
+        SDL_SetError("SDL_BlendLines(): Passed NULL destination surface");
         return -1;
     }
 
-    if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
-        r = DRAW_MUL(r, a);
-        g = DRAW_MUL(g, a);
-        b = DRAW_MUL(b, a);
-    }
-
-    /* FIXME: Does this function pointer slow things down significantly? */
-    switch (dst->format->BitsPerPixel) {
-    case 15:
-        switch (dst->format->Rmask) {
-        case 0x7C00:
-            func = SDL_BlendLine_RGB555;
-        }
-        break;
-    case 16:
-        switch (dst->format->Rmask) {
-        case 0xF800:
-            func = SDL_BlendLine_RGB565;
-        }
-        break;
-    case 32:
-        switch (dst->format->Rmask) {
-        case 0x00FF0000:
-            if (!dst->format->Amask) {
-                func = SDL_BlendLine_RGB888;
-            } else {
-                func = SDL_BlendLine_ARGB8888;
-            }
-            break;
-        }
-    default:
-        break;
-    }
-
+    func = SDL_CalculateBlendLineFunc(dst->format);
     if (!func) {
-        if (!dst->format->Amask) {
-            func = SDL_BlendLine_RGB;
-        } else {
-            func = SDL_BlendLine_RGBA;
-        }
+        SDL_SetError("SDL_BlendLines(): Unsupported surface format");
+        return -1;
     }
 
     for (i = 1; i < count; ++i) {
@@ -337,12 +765,16 @@
             continue;
         }
 
-        status = func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, SDL_FALSE);
+        /* Draw the end if it was clipped */
+        draw_end = (x2 != points[i].x || y2 != points[i].y);
+
+        func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, draw_end);
     }
     if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
-        SDL_BlendPoint(dst, points[count-1].x, points[count-1].y, r, g, b, a);
+        SDL_BlendPoint(dst, points[count-1].x, points[count-1].y,
+                       blendMode, r, g, b, a);
     }
-    return status;
+    return 0;
 }
 
 /* vi: set ts=4 sw=4 expandtab: */