9d1e6d3aee589c5a7498ea06023438fdfbbb7884
[bertos.git] / mware / gfx.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \author Bernardo Innocenti <bernie@develer.com>
12  * \author Stefano Fedrigo <aleph@develer.com>
13  *
14  * \brief General pourpose graphics routines
15  */
16
17 /*#*
18  *#* $Log$
19  *#* Revision 1.5  2004/08/25 14:12:09  rasky
20  *#* Aggiornato il comment block dei log RCS
21  *#*
22  *#* Revision 1.4  2004/08/24 16:53:10  bernie
23  *#* Use new-style config macros.
24  *#*
25  *#* Revision 1.3  2004/08/04 03:16:59  bernie
26  *#* Switch to new DevLib CONFIG_ convention.
27  *#*
28  *#* Revision 1.2  2004/06/03 11:27:09  bernie
29  *#* Add dual-license information.
30  *#*
31  *#*/
32
33 #include "gfx.h"
34 #include "config.h"
35 #include <drv/kdebug.h>
36
37 #include <string.h>
38
39
40 /*!
41  * Plot a point in bitmap.
42  * \note bm is evaluated twice
43  */
44 #define BM_PLOT(bm, x, y) \
45         ( *((bm)->raster + ((y) / 8) * (bm)->width + (x)) |= 1 << ((y) % 8) )
46
47 /*!
48  * Clear a point in bitmap.
49  * \note bm is evaluated twice
50  */
51 #define BM_CLEAR(bm, x, y) \
52         ( *((bm)->raster + ((y) / 8) * (bm)->width + (x)) &= ~(1 << ((y) % 8)) )
53
54 /*! Swap a with b */
55 #define SWAP(a, b) \
56         do { \
57                 (void)(&a == &b); /* type check */ \
58                 typeof(a) tmp; \
59                 tmp = (a); \
60                 (a) = (b); \
61                 (b) = tmp; \
62         } while (0)
63
64
65 /*!
66  * Initialize a Bitmap structure with the provided parameters.
67  */
68 void gfx_InitBitmap(Bitmap *bm, uint8_t *raster, coord_t w, coord_t h)
69 {
70         bm->raster = raster;
71         bm->width = w;
72         bm->height = h;
73         bm->penX = 0;
74         bm->penY = 0;
75 }
76
77
78 /*!
79  * Clear the whole bitmap surface to all zeros
80  */
81 void gfx_ClearBitmap(Bitmap *bm)
82 {
83         memset(bm->raster, 0, (bm->width * bm->height) / 8);
84 }
85
86
87 /*!
88  * Copy a raster picture located in program memory in the bitmap.
89  * The size of the raster to copy *must* be the same of the raster bitmap.
90  */
91 void gfx_blitBitmap_P(Bitmap *bm, const prog_uchar *raster)
92 {
93         memcpy_P(bm->raster, raster, bm->height/8 * bm->width);
94 }
95
96
97 void gfx_DrawLine(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
98 {
99         int x, y, e, len, adx, ady, signx, signy;
100
101
102 #if CONFIG_GFX_CLIPPING
103         /* FIXME: broken */
104
105         #define XMIN 0
106         #define YMIN 0
107         #define XMAX (bm->width - 1)
108         #define YMAX (bm->height - 1)
109
110         /* Clipping */
111         if (x1 < XMIN)
112         {
113                 y1 = y2 - ((x2 - XMIN) * (y2 - y1)) / (x2 - x1);
114                 x1 = XMIN;
115         }
116         if (y1 < YMIN)
117         {
118                 x1 = x2 - ((y2 - YMIN) * (x2 - x1)) / (y2 - y1);
119                 y1 = YMIN;
120         }
121         if (x2 < XMIN)
122         {
123                 y2 = y2 - ((XMIN - x1) * (y2 - y1)) / (x2 - x1);
124                 x2 = XMIN;
125         }
126         if (y2 < YMIN)
127         {
128                 x2 = x2 - ((YMIN - y1) * (x2 - x1)) / (y2 - y1);
129                 y2 = YMIN;
130         }
131
132         if (x1 > XMAX)
133         {
134                 y1 = ((x2 - XMAX) * (y2 - y1)) / (x2 - x1);
135                 x1 = XMAX;
136         }
137         if (y1 > YMAX)
138         {
139                 x1 = ((y2 - YMAX) * (x2 - x1)) / (y2 - y1);
140                 y1 = YMAX;
141         }
142         if (x2 > XMAX)
143         {
144                 y2 = ((XMAX - x1) * (y2 - y1)) / (x2 - x1);
145                 x2 = XMAX;
146         }
147         if (y2 > YMAX)
148         {
149                 x2 = ((YMAX - y1) * (x2 - x1)) / (y2 - y1);
150                 y2 = YMAX;
151         }
152
153         #undef XMIN
154         #undef YMIN
155         #undef XMAX
156         #undef YMAX
157
158 #endif /* CONFIG_GFX_CLIPPING */
159
160
161         if (x2 > x1)
162         {
163                 /* left to right */
164                 signx = +1;
165                 adx = x2 - x1;
166         }
167         else
168         {
169                 /* right to left */
170                 signx = -1;
171                 adx = x1 - x2;
172         }
173
174         if (y2 > y1)
175         {
176                 /* top to bottom */
177                 signy = +1;
178                 ady = y2 - y1;
179         }
180         else
181         {
182                 /* bottom to top */
183                 signy = -1;
184                 ady = y1 - y2;
185         }
186
187         x = x1;
188         y = y1;
189
190         if (adx > ady)
191         {
192                 /* X-major line (octants 1/4/5/8) */
193
194                 len = adx;
195                 e = -adx;
196                 while (len--)
197                 {
198                         /* Sanity check */
199                         if ((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height))
200                                 BM_PLOT(bm, x, y);
201                         x += signx;
202                         e += ady;
203                         if (e >= 0)
204                         {
205                                 y += signy;
206                                 e -= adx;
207                         }
208                 }
209         }
210         else
211         {
212                 /* Y-major line (octants 2/3/6/7) */
213
214                 len = ady;
215                 e = -ady;
216                 while (len--)
217                 {
218                         /* Sanity check */
219                         if ((x >= 0) && (x < bm->width) && (y >= 0) && (y < bm->height))
220                                 BM_PLOT(bm, x, y);
221                         y += signy;
222                         e += adx;
223                         if (e >= 0)
224                         {
225                                 x += signx;
226                                 e -= ady;
227                         }
228                 }
229         }
230 }
231
232
233 void gfx_MoveTo(Bitmap *bm, coord_t x, coord_t y)
234 {
235         bm->penX = x;
236         bm->penY = y;
237 }
238
239
240 void gfx_LineTo(Bitmap *bm, coord_t x, coord_t y)
241 {
242         gfx_DrawLine(bm, bm->penX, bm->penY, x, y);
243         gfx_MoveTo(bm, x, y);
244 }
245
246
247 /*!
248  * Draw a filled rectangle.
249  * \note The bottom-right border of the rectangle is not drawn.
250  */
251 void gfx_FillRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
252 {
253         coord_t x, y;
254
255         /* Sort coords */
256         if (x1 > x2) SWAP(x1, x2);
257         if (y1 > y2) SWAP(y1, y2);
258
259         /* Clip rect to bitmap bounds */
260         if (x1 < 0)             x1 = 0;
261         if (x2 < 0)             x2 = 0;
262         if (x1 > bm->width)     x1 = bm->width;
263         if (x2 > bm->width)     x2 = bm->width;
264         if (y1 < 0)             y1 = 0;
265         if (y2 < 0)             y2 = 0;
266         if (y1 > bm->width)     y1 = bm->width;
267         if (y2 > bm->width)     y2 = bm->width;
268
269         /* Draw rectangle */
270         for (x = x1; x < x2; x++)
271                 for (y = y1; y < y2; y++)
272                         BM_PLOT(bm, x, y);
273 }
274
275
276 /*!
277  * Draw an empty rectangle.
278  * \note The bottom-right border of the rectangle is not drawn.
279  */
280 void gfx_DrawRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
281 {
282         /* Sort coords */
283         if (x1 > x2) SWAP(x1, x2);
284         if (y1 > y2) SWAP(y1, y2);
285
286         /* Draw rectangle */
287         gfx_DrawLine(bm, x1,   y1,   x2-1, y1);
288         gfx_DrawLine(bm, x2-1, y1,   x2-1, y2-1);
289         gfx_DrawLine(bm, x2-1, y2-1, x1,   y2-1);
290         gfx_DrawLine(bm, x1,   y2-1, x1,   y1);
291 }
292
293
294 /*!
295  * Clear a rectangular area.
296  * \note The bottom-right border of the rectangle is not drawn.
297  */
298 void gfx_ClearRect(Bitmap *bm, coord_t x1, coord_t y1, coord_t x2, coord_t y2)
299 {
300         coord_t x, y;
301
302         /* Sort coords */
303         if (x1 > x2) SWAP(x1, x2);
304         if (y1 > y2) SWAP(y1, y2);
305
306         /* Clip rect to bitmap bounds */
307         if (x1 < 0)             x1 = 0;
308         if (x2 < 0)             x2 = 0;
309         if (x1 > bm->width)     x1 = bm->width;
310         if (x2 > bm->width)     x2 = bm->width;
311         if (y1 < 0)             y1 = 0;
312         if (y2 < 0)             y2 = 0;
313         if (y1 > bm->width)     y1 = bm->width;
314         if (y2 > bm->width)     y2 = bm->width;
315
316         /* Draw rectangle */
317         for (x = x1; x < x2; x++)
318                 for (y = y1; y < y2; y++)
319                         BM_CLEAR(bm, x, y);
320 }
321
322
323 /*!
324  * Imposta un rettangolo di clipping per il disegno nella bitmap
325  */
326 void gfx_SetClipRect(Bitmap *bm, coord_t minx, coord_t miny, coord_t maxx, coord_t maxy)
327 {
328         ASSERT(minx < maxx);
329         ASSERT(miny < maxy);
330         ASSERT(miny >= 0);
331         ASSERT(minx >= 0);
332         ASSERT(maxx < bm->width);
333         ASSERT(maxy < bm->height);
334
335         bm->cr.xmin = minx;
336         bm->cr.ymin = miny;
337         bm->cr.xmax = maxx;
338         bm->cr.ymax = maxy;
339
340 /*      DB(kprintf("cr.xmin = %d, cr.ymin = %d, cr.xmax = %d, cr.ymax = %d\n",
341                 bm->cr.xMin, bm->cr.ymin, bm->cr.xmax, bm->cr.ymax);)
342 */
343 }
344
345
346 #if CONFIG_GFX_VCOORDS
347 /*!
348  * Imposta gli estremi del sistema di coordinate cartesiane rispetto
349  * al rettangolo di clipping della bitmap.
350  */
351 void gfx_SetViewRect(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2)
352 {
353         ASSERT(x1 != x2);
354         ASSERT(y1 != y2);
355
356         bm->orgX    = x1;
357         bm->orgY    = y1;
358         bm->scaleX  = (vcoord_t)(bm->cr.xmax - bm->cr.xmin) / (vcoord_t)(x2 - x1);   /* +1 */
359         bm->scaleY  = (vcoord_t)(bm->cr.ymax - bm->cr.ymin) / (vcoord_t)(y2 - y1);   /* +1 */
360
361 /*      DB(kprintf("orgX = %f, orgY = %f, scaleX = %f, scaleY = %f\n",
362                 bm->orgX, bm->orgY, bm->scaleX, bm->scaleY);)
363 */
364 }
365
366
367 /*!
368  * Transform a coordinate from the current reference system to a
369  * pixel offset within the bitmap.
370  */
371 coord_t gfx_TransformX(Bitmap *bm, vcoord_t x)
372 {
373         return bm->cr.xmin + (coord_t)((x - bm->orgX) * bm->scaleX);
374 }
375
376 /*!
377  * Transform a coordinate from the current reference system to a
378  * pixel offset within the bitmap.
379  */
380 coord_t gfx_TransformY(Bitmap *bm, vcoord_t y)
381 {
382         return bm->cr.ymin + (coord_t)((y - bm->orgY) * bm->scaleY);
383 }
384
385
386 /*!
387  * Draw a line from (x1;y1) to (x2;y2)
388  */
389 void gfx_VDrawLine(Bitmap *bm, vcoord_t x1, vcoord_t y1, vcoord_t x2, vcoord_t y2)
390 {
391         gfx_DrawLine(bm,
392                 gfx_TransformX(bm, x1), gfx_TransformY(bm, y1),
393                 gfx_TransformY(bm, x2), gfx_TransformY(bm, y2));
394 }
395 #endif /* CONFIG_GFX_VCOORDS */