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