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