BeRTOS
|
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 */