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