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