changeset 133:92cc5e1fa180

Some work on line drawing routines.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 05 Oct 2012 00:36:40 +0300
parents b5569c84f00a
children 1ba202b448e0
files dmdrawline.h dmline.c dmlinefunc.h
diffstat 3 files changed, 284 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/dmdrawline.h	Thu Oct 04 15:43:10 2012 +0300
+++ b/dmdrawline.h	Fri Oct 05 00:36:40 2012 +0300
@@ -5,13 +5,14 @@
     const int qpitch = screen->pitch / DM_DRAWLINE_DST_BYTES;
 
     // Clipping
-    if (dmClipLineCoords(&x0, &y0, &x1, &y1, screen))
+    if (dmClipLineCoords(&x0, &y0, &x1, &y1, screen) < 0)
         return -1;
 
     // Compute initial deltas
     dx = (x1 - x0) * 2;
     dy = (y1 - y0) * 2;
 
+
     if (dx < 0)
     {
         dx = -dx;
@@ -32,7 +33,11 @@
     y0 *= qpitch;
     y1 *= qpitch;
 
-    DM_DRAWLINE_DST_TYPE *pix = screen->pixels;
+#ifdef DM_DRAWLINE_INIT
+    DM_DRAWLINE_INIT
+#endif
+
+    DM_DRAWLINE_DST_TYPE *pix = (DM_DRAWLINE_DST_TYPE *) screen->pixels;
 
     // Continue based on which delta is larger
     if (dx > dy)
@@ -76,3 +81,5 @@
 #undef DM_DRAWLINE_NAME
 #undef DM_DRAWLINE_DST_BYTES
 #undef DM_DRAWLINE_DST_TYPE
+#undef DM_DRAWLINE_INIT
+#undef DM_DRAWLINE_INNER
--- a/dmline.c	Thu Oct 04 15:43:10 2012 +0300
+++ b/dmline.c	Fri Oct 05 00:36:40 2012 +0300
@@ -12,45 +12,264 @@
  * > 0  : Clipped. Line partially inside the clipping area.
  * < 0  : Line completely outside the clipping area.
  */
+#define dmClipBits(Q, x, y)	\
+    do {			\
+        Q = 0;			\
+        if (x < clipX0) Q |= 1;	\
+        else			\
+        if (x > clipX1) Q |= 2;	\
+        if (y < clipY0) Q |= 4;	\
+        else			\
+        if (y > clipY1) Q |= 8;	\
+    } while (0)
+
+#define xA (*x0)
+#define xB (*x1)
+#define yA (*y0)
+#define yB (*y1)
+
 int dmClipLineCoords(int *x0, int *y0, int *x1, int *y1, SDL_Surface *screen)
 {
-#if 0
     const int clipX0 = screen->clip_rect.x,
               clipY0 = screen->clip_rect.y;
     const int clipX1 = clipX0 + screen->clip_rect.w - 1,
               clipY1 = clipY0 + screen->clip_rect.h - 1;
-    const int dx = *x1 - *x0,
-              dy = *y1 - *y0;
-    DMFixedPoint k, kdx, kdy;
+
+    int cA, cB;
+
+    dmClipBits(cA, xA, yA);
+    dmClipBits(cB, xB, yB);
+
+    if (cA & cB)
+        return -1;              /* the line segment is outside */
+
+    if ((cA | cB) == 0)         /* the line segment is inside of the clipping rectangle */
+        return 0;
+
+#if 1
+    // Cohen-Sutherland clipping method
+    do
+    {
+        const int c = cA ? cA : cB;
+        int x, y;
+        
+        if (c & 1)
+        {
+            y = yA + ((clipX0 - xA)*(yB - yA)) / (xB - xA);
+            x = clipX0;
+        }
+        else
+        if (c & 2)
+        {
+            y = yA + ((clipX1 - xA)*(yB - yA)) / (xB - xA);
+            x = clipX1;
+        }
+        else
+        if (c & 4)
+        {
+            x = xA + ((clipY0 - yA)*(xB - xA)) / (yB - yA);
+            y = clipY0;
+        }
+        else
+        if (c & 8)
+        {
+            x = xA + ((clipY1 - yA)*(xB - xA)) / (yB - yA);
+            y = clipY1;
+        }
+
+        if (c == cA)
+        {
+            xA = x;
+            yA = y;
+            dmClipBits(cA, xA, yA);
+        }
+        else
+        {
+            xB = x;
+            yB = y;
+            dmClipBits(cB, xB, yB);
+        }
+        
+    } while (cA | cB);
+#else
+    // Buyu-Skala clipping method
+    const int dx = xB - xA;
+    const int dy = yB - yA;
+    float k, m;
+    int z;
+
+    switch (cA + cB)
+    {
+        case 1:
+            if (cA == 1)
+            {
+                xA = clipX0;
+                yA = (clipX0 - xB) * dy / dx + yB;
+            }
+            else
+            {
+                xB = clipX0;
+                yB = (clipX0 - xA) * dy / dx + yA;
+            }
+            break;
+
+        case 3:
+            k = dy / dx;
+            yA = (clipX0 - xA) * k + yA;
+            xA = clipX0;
+            yB = (clipX1 - xB) * k + yB;
+            xB = clipX1;
+            break;
+
+        case 5:
+            k = dy / dx;
+            z = (clipX0 - xA) * k + yA;
+            if (z < clipY0)
+            {
+                switch (cA)
+                {
+                    case 0:
+                        xB = xB + (clipY0 - yB) / k;
+                        yB = clipY0;
+                        break;
+                    case 5:
+                        xA = xA + (clipY0 - yA) / k;
+                        yA = clipY0;
+                        break;
 
-    // Is line completely outside the clipping area?
-    if ((*x0 < clipX0 && *x1 < clipX0) || (*x0 > clipX1 && *x1 > clipX1) ||
-        (*y0 < clipY0 && *y1 < clipY0) || (*y0 > clipY1 && *y1 > clipY1))
-        return -1;
-    
-    FP_SETHL(kdx, dx);
-    FP_SETHL(kdy, dy);
-#endif        
-    
-    return 0;
+                    default:
+                        return -1;  /* the line segment is outside */
+                }
+            }
+            else
+            {
+                switch (cA)
+                {
+                    case 0:
+                        xB = clipX0;
+                        yB = z;
+                        break;
+                    case 1:
+                        xB = xB + (clipY0 - yB) / k;
+                        yB = clipY0;
+                        xA = clipX0;
+                        yA = z;
+                        break;
+                    case 4:
+                        xA = xA + (clipY0 - yA) / k;
+                        yA = clipY0;
+                        xB = clipX0;
+                        yB = z;
+                        break;
+                    case 5:
+                        xA = clipX0;
+                        yA = z;
+                        break;
+                }
+            }
+            break;
+
+        case 7:
+            switch (cA)
+            {
+                case 1:
+                    k = dy / dx;
+                    yA = (clipX0 - xB) * k + yB;
+                    if (yA < clipY0)
+                        return -1;  /* the line segment is outside */
+                    xA = clipX0;
+                    yB = (clipX1 - clipX0) * k + yA;
+                    if (yB < clipY0)
+                    {
+                        xB = (clipY0 - yB) / k + clipX1;
+                        yB = clipY0;
+                    }
+                    else
+                        xB = clipX1;
+                    break;
+
+                    /* similarly for cases cA == 2, 5, 6 */
+            }
+        case 15:
+            switch (cA)
+            {
+            case 5:
+                if (dy * (clipX1 - clipX0) < dx * (clipY1 - clipY0))
+                {
+                    k = dy / dx;
+                    yA = (clipX0 - xB) * k + yB;
+                    if (yA > clipY1)
+                        return -1;  /* the line segment is outside */
+                    yB = (clipX1 - clipX0) * k + yA;
+                    if (yB < clipY0)
+                        return -1;  /* the line segment is outside */
+                    if (yA < clipY0)
+                    {
+                        xA = (clipY0 - yA) / k + clipX0;
+                        yA = clipY0;
+                        xB = clipX1;
+                    }
+                    else
+                    {
+                        xA = clipX0;
+                        if (yB > clipY1)
+                        {
+                            xB = (clipY1 - yB) / k + clipX1;
+                            yB = clipY1;
+                        }
+                        else
+                            xB = clipX1;
+                    }
+                }
+                else
+                {
+                    m = dx / dy;
+                    xA = (clipY0 - yB) * m + xB;
+                    if (xA > clipX1)
+                        return -1;  /* the line segment is outside */
+                    xB = (clipY1 - clipY0) * m + xA;
+                    if (xB < clipX0)
+                        return -1;  /* the line segment is outside */
+                    if (xA < clipX0)
+                    {
+                        yA = (clipX0 - xA) / m + clipY0;
+                        xA = clipX0;
+                        yB = clipY1;
+                    }
+                    else
+                    {
+                        yA = clipY0;
+                        if (xB > clipX1)
+                        {
+                            yB = (clipX1 - xB) / m + clipY1;
+                            xB = clipX1;
+                        }
+                        else
+                            yB = clipY1;
+                    }
+                }
+
+                /* similarly for cases cA == 6, 9, 10 */
+            }
+
+            /* cases 2, 4, 8 are similar as case 1, cases 6, 9, 10 are similar as case 5 */
+            /* cases 11, 13, 14 are similar as case 7, case 12 is similar case 3 */
+    }                           /* of case cA + cB */
+#endif
+
+    return 1;
 }
 
 
-int dmTestLineCoords(int x0, int y0, int x1, int y1, SDL_Surface *screen)
-{
-    return dmClipLineCoords(&x0, &y0, &x1, &y1, screen);
-}
-
 
 #include "dmlinefunc.h"
 
 static const DMDrawLineFunc dmDrawLineTable[DMD_NMODES][DMD_NBITDEPTHS] =
 {
     /* DMD_NONE          */ { dmDrawLine8              , dmDrawLine32 },
-#if 0
     /* DMD_TRANSPARENT   */ { dmDrawLine8Transparent   , dmDrawLine32Transparent },
     /* DMD_SATURATE      */ { dmDrawLine8Saturate      , dmDrawLine32Saturate },
-
+#if 0
     /* DMD_NONE + AA     */ { NULL, NULL },
     /* DMD_TRANSP + AA   */ { NULL, NULL },
     /* DMD_SATURATE + AA */ { dmDrawLine8AASaturate    , dmDrawLine32AASaturate },
--- a/dmlinefunc.h	Thu Oct 04 15:43:10 2012 +0300
+++ b/dmlinefunc.h	Fri Oct 05 00:36:40 2012 +0300
@@ -1,10 +1,9 @@
-
-#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
-
 
 #define DM_DRAWLINE_NAME dmDrawLine8
 #define DM_DRAWLINE_DST_BYTES 1
 #define DM_DRAWLINE_DST_TYPE Uint8
+#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
+#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
 #include "dmdrawline.h"
 
 
@@ -14,34 +13,47 @@
 #include "dmdrawline.h"
 
 
-/*
-#undef DM_DRAWLINE_INNER
+#define DM_DRAWLINE_NAME dmDrawLine8Transparent
+#define DM_DRAWLINE_DST_BYTES 1
+#define DM_DRAWLINE_DST_TYPE Uint8
 #define DM_DRAWLINE_INNER \
-  int q = pix[y0 + x0] + col;
-  pix[y0 + x0] = q > 
+  pix[y0 + x0] = ((int)pix[y0 + x0] + col) >> 1;
+#include "dmdrawline.h"
 
 
-#define DM_DRAWLINE_NAME dmDrawLineAdd8
-#define DM_DRAWLINE_DST_BYTES 1
-#define DM_DRAWLINE_DST_TYPE Uint8
+#define DM_DRAWLINE_NAME dmDrawLine32Transparent
+#define DM_DRAWLINE_DST_BYTES 4
+#define DM_DRAWLINE_DST_TYPE DMRGBA32
+#define DM_DRAWLINE_INIT const DMRGBA32 *c = (DMRGBA32*) &col;
+#define DM_DRAWLINE_INNER \
+  const DMRGBA32 q = pix[y0 + x0]; \
+  const int qr = (q.r + c->r) >> 1, qg = (q.g + c->g) >> 1, qb = (q.b + c->b) >> 1;  \
+  pix[y0 + x0].r = qr; \
+  pix[y0 + x0].g = qg; \
+  pix[y0 + x0].b = qb;
 #include "dmdrawline.h"
 
 
-#define DM_DRAWLINE_NAME dmDrawLineAdd15
-#define DM_DRAWLINE_DST_BYTES 2
-#define DM_DRAWLINE_DST_TYPE Uint16
+
+
+#define DM_DRAWLINE_NAME dmDrawLine8Saturate
+#define DM_DRAWLINE_DST_BYTES 1
+#define DM_DRAWLINE_DST_TYPE Uint8
+#define DM_DRAWLINE_INNER \
+  const int q = pix[y0 + x0] + col; \
+  pix[y0 + x0] = q < 255 ? q : 255;
 #include "dmdrawline.h"
 
 
-#define DM_DRAWLINE_NAME dmDrawLineAdd16
-#define DM_DRAWLINE_DST_BYTES 2
-#define DM_DRAWLINE_DST_TYPE Uint16
+#define DM_DRAWLINE_NAME dmDrawLine32Saturate
+#define DM_DRAWLINE_DST_BYTES 4
+#define DM_DRAWLINE_DST_TYPE DMRGBA32
+#define DM_DRAWLINE_INIT const DMRGBA32 *c = (DMRGBA32*) &col;
+#define DM_DRAWLINE_INNER \
+  const DMRGBA32 q = pix[y0 + x0]; \
+  const int qr = q.r + c->r, qg = q.g + c->g, qb = q.b + c->b;  \
+  pix[y0 + x0].r = qr < 255 ? qr : 255; \
+  pix[y0 + x0].g = qg < 255 ? qg : 255; \
+  pix[y0 + x0].b = qb < 255 ? qb : 255;
 #include "dmdrawline.h"
 
-
-#define DM_DRAWLINE_NAME dmDrawLineAdd32
-#define DM_DRAWLINE_DST_BYTES 4
-#define DM_DRAWLINE_DST_TYPE Uint32
-#include "dmdrawline.h"
-*/
-