4 * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5 * Copyright 1999 Bernardo Innocenti <bernie@develer.com>
6 * This file is part of DevLib - See README.devlib for information.
11 * \author Bernardo Innocenti <bernie@develer.com>
12 * \author Stefano Fedrigo <aleph@develer.com>
14 * \brief Line drawing graphics routines
19 *#* Revision 1.1 2006/01/24 02:17:49 bernie
20 *#* Split out gfx.c into bitmap.c and line.c.
27 #include <cfg/debug.h> /* ASSERT() */
28 #include <cfg/cpu.h> /* CPU_HARVARD */
29 #include <cfg/macros.h> /* SWAP() */
30 #include <appconfig.h> /* CONFIG_GFX_CLIPPING */
33 * Draw a sloped line without performing clipping.
35 * Parameters are the same of gfx_line().
36 * This routine is based on the Bresenham Line-Drawing Algorithm.
38 * \note Passing coordinates outside the bitmap boundaries will
39 * result in memory trashing.
41 * \todo Optimize for vertical and horiziontal lines.
45 static void gfx_lineUnclipped(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
47 int x, y, e, len, adx, ady, signx, signy;
80 /* X-major line (octants 1/4/5/8) */
87 ASSERT((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height));
100 /* Y-major line (octants 2/3/6/7) */
107 ASSERT ((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height));
120 //! Helper routine for gfx_line().
121 static int gfx_findRegion(int x, int y, Rect *cr)
126 code |= 1; /* below */
127 else if (y < cr->ymin)
128 code |= 2; /* above */
131 code |= 4; /* right */
132 else if (x < cr->xmin)
133 code |= 8; /* left */
139 * Draw a sloped line segment.
141 * Draw a sloped line segment identified by the provided
142 * start and end coordinates on the bitmap \a bm.
144 * The line endpoints are clipped inside the current bitmap
145 * clipping rectangle using the Cohen-Sutherland algorithm,
146 * which is very fast.
148 * \note The point at coordinates \a x2 \a y2 is not drawn.
150 * \note This function does \b not update the current pen position.
152 * \todo Compute updated Bresenham error term.
154 void gfx_line(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
156 #if CONFIG_GFX_CLIPPING
157 int clip1 = gfx_findRegion(x1, y1, &bm->cr);
158 int clip2 = gfx_findRegion(x2, y2, &bm->cr);
160 /* Loop while there is at least one point outside */
161 while (clip1 | clip2)
163 /* Check for line totally outside */
167 int c = clip1 ? clip1 : clip2;
170 if (c & 1) /* Below */
172 x = x1 + (x2 - x1) * (bm->cr.ymax - y1) / (y2 - y1);
175 else if (c & 2) /* Above */
177 x = x1 + (x2 - x1) * (bm->cr.ymin - y1) / (y2 - y1);
180 else if (c & 4) /* Right */
182 y = y1 + (y2 - y1) * (bm->cr.xmax - x1) / (x2 - x1);
187 y = y1 + (y2 - y1) * (bm->cr.xmin - x1) / (x2 - x1);
191 if (c == clip1) /* First endpoint was clipped */
193 // TODO: adjust Bresenham error term
194 //coord_t clipdx = ABS(x - x1);
195 //coord_t clipdy = ABS(y - y1);
196 //e += (clipdy * e2) + ((clipdx - clipdy) * e1);
200 clip1 = gfx_findRegion(x1, y1, &bm->cr);
202 else /* Second endpoint was clipped */
206 clip2 = gfx_findRegion(x2, y2, &bm->cr);
209 #endif /* CONFIG_GFX_CLIPPING */
211 gfx_lineUnclipped(bm, x1, y1, x2, y2);
215 * Move the current pen position to the specified coordinates.
217 * The pen position is used for drawing operations such as
218 * gfx_lineTo(), which can be used to draw polygons.
220 void gfx_moveTo(Bitmap *bm, coord_t x, coord_t y)
227 * Draw a line from the current pen position to the new coordinates.
229 * \note This function moves the current pen position to the
234 void gfx_lineTo(Bitmap *bm, coord_t x, coord_t y)
236 gfx_line(bm, bm->penX, bm->penY, x, y);
237 gfx_moveTo(bm, x, y);
242 * Draw the perimeter of an hollow rectangle.
244 * \note The bottom-right corner of the rectangle is drawn at (x2-1;y2-1).
245 * \note This function does \b not update the current pen position.
247 void gfx_rectDraw(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
249 /* Sort coords (needed for correct bottom-right semantics) */
250 if (x1 > x2) SWAP(x1, x2);
251 if (y1 > y2) SWAP(y1, y2);
254 gfx_line(bm, x1, y1, x2-1, y1);
255 gfx_line(bm, x2-1, y1, x2-1, y2-1);
256 gfx_line(bm, x2-1, y2-1, x1, y2-1);
257 gfx_line(bm, x1, y2-1, x1, y1);
262 * Fill a rectangular area with \a color.
264 * \note The bottom-right border of the rectangle is not drawn.
266 * \note This function does \b not update the current pen position.
268 void gfx_rectFillC(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t color)
273 if (x1 > x2) SWAP(x1, x2);
274 if (y1 > y2) SWAP(y1, y2);
276 #if CONFIG_GFX_CLIPPING
277 /* Clip rect to bitmap clip region */
278 if (x1 < bm->cr.xmin) x1 = bm->cr.xmin;
279 if (x2 < bm->cr.xmin) x2 = bm->cr.xmin;
280 if (x1 > bm->cr.xmax) x1 = bm->cr.xmax;
281 if (x2 > bm->cr.xmax) x2 = bm->cr.xmax;
282 if (y1 < bm->cr.ymin) y1 = bm->cr.ymin;
283 if (y2 < bm->cr.ymin) y2 = bm->cr.ymin;
284 if (y1 > bm->cr.ymax) y1 = bm->cr.ymax;
285 if (y2 > bm->cr.ymax) y2 = bm->cr.ymax;
288 /* NOTE: Code paths are duplicated for efficiency */
289 if (color) /* fill */
291 for (x = x1; x < x2; x++)
292 for (y = y1; y < y2; y++)
297 for (x = x1; x < x2; x++)
298 for (y = y1; y < y2; y++)
305 * Draw a filled rectangle.
307 * \note The bottom-right border of the rectangle is not drawn.
309 * \note This function does \b not update the current pen position.
311 void gfx_rectFill(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
313 gfx_rectFillC(bm, x1, y1, x2, y2, 0xFF);
318 * Clear a rectangular area.
320 * \note The bottom-right border of the rectangle is not cleared.
322 * \note This function does \b not update the current pen position.
324 void gfx_rectClear(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
326 gfx_rectFillC(bm, x1, y1, x2, y2, 0x00);
330 #if CONFIG_GFX_VCOORDS
332 * Imposta gli estremi del sistema di coordinate cartesiane rispetto
333 * al rettangolo di clipping della bitmap.
335 void gfx_setViewRect(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2)
342 bm->scaleX = (vcoord_t)(bm->cr.xmax - bm->cr.xmin - 1) / (vcoord_t)(x2 - x1);
343 bm->scaleY = (vcoord_t)(bm->cr.ymax - bm->cr.ymin - 1) / (vcoord_t)(y2 - y1);
345 /* DB(kprintf("orgX = %f, orgY = %f, scaleX = %f, scaleY = %f\n",
346 bm->orgX, bm->orgY, bm->scaleX, bm->scaleY);)
352 * Transform a coordinate from the current reference system to a
353 * pixel offset within the bitmap.
355 coord_t gfx_transformX(Bitmap *bm, vcoord_t x)
357 return bm->cr.xmin + (coord_t)((x - bm->orgX) * bm->scaleX);
361 * Transform a coordinate from the current reference system to a
362 * pixel offset within the bitmap.
364 coord_t gfx_transformY(Bitmap *bm, vcoord_t y)
366 return bm->cr.ymin + (coord_t)((y - bm->orgY) * bm->scaleY);
371 * Draw a line from (x1;y1) to (x2;y2).
373 void gfx_vline(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2)
376 gfx_transformX(bm, x1), gfx_transformY(bm, y1),
377 gfx_transformY(bm, x2), gfx_transformY(bm, y2));
379 #endif /* CONFIG_GFX_VCOORDS */