line.c

Go to the documentation of this file.
00001 
00043 #include "gfx.h"
00044 #include "gfx_p.h"
00045 
00046 #include "cfg/cfg_gfx.h"   /* CONFIG_GFX_CLIPPING */
00047 #include <cfg/debug.h>   /* ASSERT() */
00048 #include <cfg/macros.h>  /* SWAP() */
00049 
00050 /* Configuration sanity checks */
00051 #if !defined(CONFIG_GFX_CLIPPING) || (CONFIG_GFX_CLIPPING != 0 && CONFIG_GFX_CLIPPING != 1)
00052     #error CONFIG_GFX_CLIPPING must be defined to either 0 or 1
00053 #endif
00054 #if !defined(CONFIG_GFX_VCOORDS) || (CONFIG_GFX_VCOORDS != 0 && CONFIG_GFX_VCOORDS != 1)
00055     #error CONFIG_GFX_VCOORDS must be defined to either 0 or 1
00056 #endif
00057 
00071 static void gfx_lineUnclipped(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
00072 {
00073     int x, y, e, len, adx, ady, signx, signy;
00074 
00075     if (x2 > x1)
00076     {
00077         /* left to right */
00078         signx = +1;
00079         adx = x2 - x1;
00080     }
00081     else
00082     {
00083         /* right to left */
00084         signx = -1;
00085         adx = x1 - x2;
00086     }
00087 
00088     if (y2 > y1)
00089     {
00090         /* top to bottom */
00091         signy = +1;
00092         ady = y2 - y1;
00093     }
00094     else
00095     {
00096         /* bottom to top */
00097         signy = -1;
00098         ady = y1 - y2;
00099     }
00100 
00101     x = x1;
00102     y = y1;
00103 
00104     if (adx > ady)
00105     {
00106         /* X-major line (octants 1/4/5/8) */
00107 
00108         len = adx;
00109         e = -adx;
00110         while (len--)
00111         {
00112             /* Sanity check */
00113             ASSERT((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height));
00114             BM_PLOT(bm, x, y);
00115             x += signx;
00116             e += ady;
00117             if (e >= 0)
00118             {
00119                 y += signy;
00120                 e -= adx;
00121             }
00122         }
00123     }
00124     else
00125     {
00126         /* Y-major line (octants 2/3/6/7) */
00127 
00128         len = ady;
00129         e = -ady;
00130         while (len--)
00131         {
00132             /* Sanity check */
00133             ASSERT ((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height));
00134             BM_PLOT(bm, x, y);
00135             y += signy;
00136             e += adx;
00137             if (e >= 0)
00138             {
00139                 x += signx;
00140                 e -= ady;
00141             }
00142         }
00143     }
00144 }
00145 
00146 #if CONFIG_GFX_CLIPPING
00147 
00149 static int gfx_findRegion(int x, int y, Rect *cr)
00150 {
00151     int code = 0;
00152 
00153     if (y >= cr->ymax)
00154         code |= 1; /* below */
00155     else if (y < cr->ymin)
00156         code |= 2; /* above */
00157 
00158     if (x >= cr->xmax)
00159         code |= 4; /* right */
00160     else if (x < cr->xmin)
00161         code |= 8; /* left */
00162 
00163     return code;
00164 }
00165 
00166 #endif /* CONFIG_CLIPPING */
00167 
00184 void gfx_line(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
00185 {
00186 #if CONFIG_GFX_CLIPPING
00187     int clip1 = gfx_findRegion(x1, y1, &bm->cr);
00188     int clip2 = gfx_findRegion(x2, y2, &bm->cr);
00189 
00190     /* Loop while there is at least one point outside */
00191     while (clip1 | clip2)
00192     {
00193         /* Check for line totally outside */
00194         if (clip1 & clip2)
00195             return;
00196 
00197         int c = clip1 ? clip1 : clip2;
00198         int x, y;
00199 
00200         if (c & 1) /* Below */
00201         {
00202             x = x1 + (x2 - x1) * (bm->cr.ymax - y1) / (y2 - y1);
00203             y = bm->cr.ymax - 1;
00204         }
00205         else if (c & 2) /* Above */
00206         {
00207             x = x1 + (x2 - x1) * (bm->cr.ymin - y1) / (y2 - y1);
00208             y = bm->cr.ymin;
00209         }
00210         else if (c & 4) /* Right */
00211         {
00212             y = y1 + (y2 - y1) * (bm->cr.xmax - x1) / (x2 - x1);
00213             x = bm->cr.xmax - 1;
00214         }
00215         else /* Left */
00216         {
00217             y = y1 + (y2 - y1) * (bm->cr.xmin - x1) / (x2 - x1);
00218             x = bm->cr.xmin;
00219         }
00220 
00221         if (c == clip1) /* First endpoint was clipped */
00222         {
00223             // TODO: adjust Bresenham error term
00224             //coord_t clipdx = ABS(x - x1);
00225             //coord_t clipdy = ABS(y - y1);
00226             //e += (clipdy * e2) + ((clipdx - clipdy) * e1);
00227 
00228             x1 = x;
00229             y1 = y;
00230             clip1 = gfx_findRegion(x1, y1, &bm->cr);
00231         }
00232         else /* Second endpoint was clipped */
00233         {
00234             x2 = x;
00235             y2 = y;
00236             clip2 = gfx_findRegion(x2, y2, &bm->cr);
00237         }
00238     }
00239 #endif /* CONFIG_GFX_CLIPPING */
00240 
00241     gfx_lineUnclipped(bm, x1, y1, x2, y2);
00242 }
00243 
00250 void gfx_moveTo(Bitmap *bm, coord_t x, coord_t y)
00251 {
00252     bm->penX = x;
00253     bm->penY = y;
00254 }
00255 
00264 void gfx_lineTo(Bitmap *bm, coord_t x, coord_t y)
00265 {
00266     gfx_line(bm, bm->penX, bm->penY, x, y);
00267     gfx_moveTo(bm, x, y);
00268 }
00269 
00270 
00277 void gfx_rectDraw(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
00278 {
00279     /* Sort coords (needed for correct bottom-right semantics) */
00280     if (x1 > x2) SWAP(x1, x2);
00281     if (y1 > y2) SWAP(y1, y2);
00282 
00283     /* Draw rectangle */
00284     gfx_line(bm, x1,   y1,   x2-1, y1);
00285     gfx_line(bm, x2-1, y1,   x2-1, y2-1);
00286     gfx_line(bm, x2-1, y2-1, x1,   y2-1);
00287     gfx_line(bm, x1,   y2-1, x1,   y1);
00288 }
00289 
00290 
00298 void gfx_rectFillC(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t color)
00299 {
00300     coord_t x, y;
00301 
00302     /* Sort coords */
00303     if (x1 > x2) SWAP(x1, x2);
00304     if (y1 > y2) SWAP(y1, y2);
00305 
00306 #if CONFIG_GFX_CLIPPING
00307     /* Clip rect to bitmap clip region */
00308     if (x1 < bm->cr.xmin)   x1 = bm->cr.xmin;
00309     if (x2 < bm->cr.xmin)   x2 = bm->cr.xmin;
00310     if (x1 > bm->cr.xmax)   x1 = bm->cr.xmax;
00311     if (x2 > bm->cr.xmax)   x2 = bm->cr.xmax;
00312     if (y1 < bm->cr.ymin)   y1 = bm->cr.ymin;
00313     if (y2 < bm->cr.ymin)   y2 = bm->cr.ymin;
00314     if (y1 > bm->cr.ymax)   y1 = bm->cr.ymax;
00315     if (y2 > bm->cr.ymax)   y2 = bm->cr.ymax;
00316 #endif /* CONFIG_GFX_CLIPPING */
00317 
00318     /* NOTE: Code paths are duplicated for efficiency */
00319     if (color) /* fill */
00320     {
00321         for (x = x1; x < x2; x++)
00322             for (y = y1; y < y2; y++)
00323                 BM_PLOT(bm, x, y);
00324     }
00325     else /* clear */
00326     {
00327         for (x = x1; x < x2; x++)
00328             for (y = y1; y < y2; y++)
00329                 BM_CLEAR(bm, x, y);
00330     }
00331 }
00332 
00333 
00341 void gfx_rectFill(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
00342 {
00343     gfx_rectFillC(bm, x1, y1, x2, y2, 0xFF);
00344 }
00345 
00346 
00354 void gfx_rectClear(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
00355 {
00356     gfx_rectFillC(bm, x1, y1, x2, y2, 0x00);
00357 }
00358 
00359 
00360 #if CONFIG_GFX_VCOORDS
00361 
00365 void gfx_setViewRect(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2)
00366 {
00367     ASSERT(x1 != x2);
00368     ASSERT(y1 != y2);
00369 
00370     bm->orgX    = x1;
00371     bm->orgY    = y1;
00372     bm->scaleX  = (vcoord_t)(bm->cr.xmax - bm->cr.xmin - 1) / (vcoord_t)(x2 - x1);
00373     bm->scaleY  = (vcoord_t)(bm->cr.ymax - bm->cr.ymin - 1) / (vcoord_t)(y2 - y1);
00374 
00375 /*  DB(kprintf("orgX = %f, orgY = %f, scaleX = %f, scaleY = %f\n",
00376         bm->orgX, bm->orgY, bm->scaleX, bm->scaleY);)
00377 */
00378 }
00379 
00380 
00385 coord_t gfx_transformX(Bitmap *bm, vcoord_t x)
00386 {
00387     return bm->cr.xmin + (coord_t)((x - bm->orgX) * bm->scaleX);
00388 }
00389 
00394 coord_t gfx_transformY(Bitmap *bm, vcoord_t y)
00395 {
00396     return bm->cr.ymin + (coord_t)((y - bm->orgY) * bm->scaleY);
00397 }
00398 
00399 
00403 void gfx_vline(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2)
00404 {
00405     gfx_line(bm,
00406         gfx_transformX(bm, x1), gfx_transformY(bm, y1),
00407         gfx_transformY(bm, x2), gfx_transformY(bm, y2));
00408 }
00409 #endif /* CONFIG_GFX_VCOORDS */