4 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See README.devlib for information.
9 * \author Massimiliano Corsini <chad@develer.com>
12 * \brief Low-level drawing routines.
14 * This file contains the implementation of the low-level drawing routines
15 * to draw fill rectangle, fill triangle and so on.
21 *#* Revision 1.1 2006/07/19 13:00:01 bernie
22 *#* Import into DevLib.
24 *#* Revision 1.10 2005/10/15 15:03:43 rasky
25 *#* Remove per-pixel clipping from line().
26 *#* Use clipLine() also for a-scope.
28 *#* Revision 1.9 2005/10/14 15:21:32 eldes
29 *#* Implement the cohen-sutherland clipping on the buffer
31 *#* Revision 1.8 2005/09/27 13:28:10 rasky
32 *#* Add clipping capabilities to line()
33 *#* Fix off-by-one computation of rectangles of drawing.
35 *#* Revision 1.7 2005/09/27 10:41:35 rasky
36 *#* Import line-drawing routine from Devlib
38 *#* Revision 1.6 2005/09/19 16:36:05 chad
39 *#* Fix doxygen autobrief
41 *#* Revision 1.5 2005/07/06 12:51:47 chad
42 *#* Make the fillRectangle() independent of the order of the points of the rectangle
44 *#* Revision 1.4 2005/06/17 15:06:36 chad
45 *#* Remove conversion warning
47 *#* Revision 1.3 2005/06/17 15:04:47 chad
48 *#* Add line clipping capability
50 *#* Revision 1.2 2005/06/15 14:04:43 chad
53 *#* Revision 1.1 2005/06/15 13:34:34 chad
54 *#* Low-level drawing routines
58 // Qt-specific headers
63 * Low-level routine to draw a line.
65 * This routine is based on the Bresenham Line-Drawing Algorithm.
67 * The \a stride represents the width of the image buffer.
68 * (\a x1, \a y1) are the coordinates of the starting point.
69 * (\a x2, \a y2) are the coordinates of the ending point.
71 * The line has no anti-alias, and clipping is not performed. The line
72 * must be fully contained in the buffer (use clipLine() if you need
75 void line(unsigned char *buf,
76 unsigned long bufw, unsigned long bufh, unsigned long stride,
77 int x1, int y1, int x2, int y2, unsigned char color)
79 int x, y, e, len, adx, ady, signx, signy;
112 /* X-major line (octants 1/4/5/8) */
118 assert(y >= 0 && y < static_cast<int>(bufh) &&
119 x >= 0 && x < static_cast<int>(bufw));
120 buf[y * stride + x] = color;
132 /* Y-major line (octants 2/3/6/7) */
138 assert(y >= 0 && y < static_cast<int>(bufh) &&
139 x >= 0 && x < static_cast<int>(bufw));
140 buf[y * stride + x] = color;
152 /// Helper routine for clipLine().
153 static int region(int x, int y, int w, int h)
171 * Low-level routine to draw a line, clipped to the buffer extents.
173 * This routine executes the clipping, and then invokes line().
174 * Parameters are the same of line(). The clipping is performed
175 * using the Cohen-Sutherland algorithm, which is very fast.
177 void clipLine(unsigned char *buf,
178 unsigned long w, unsigned long h, unsigned long stride,
179 int x1, int y1, int x2, int y2, unsigned char color)
181 int code1 = region(x1, y1, w, h);
182 int code2 = region(x2, y2, w, h);
184 // Loop while there is at least one point outside
185 while (code1 | code2)
187 // Check for line totally outside
191 int c = code1 ? code1 : code2;
196 x = x1 + (x2 - x1) * (h - y1) / (y2 - y1);
199 else if (c & 2) //bottom
201 x = x1 + (x2 - x1) * -y1 / (y2 - y1);
204 else if (c & 4) //right
206 y = y1 + (y2 - y1) * (w - x1) / (x2 - x1);
211 y = y1 + (y2 - y1) * -x1 / (x2 - x1);
215 if (c == code1) // first endpoint was clipped
218 code1 = region(x1, y1, w, h);
220 else //second endpoint was clipped
223 code2 = region(x2, y2, w, h);
227 line(buf, w, h, stride, x1, y1, x2, y2, color);
232 * Low-level routine to draw a filled rectangle.
234 * The triangle is filled with the given color.
236 * The \a stride represents the width of the image buffer.
237 * The points \a p1 and \a p2 are two opposite corners of the
240 void fillRectangle(unsigned char *buf, unsigned long stride,
241 QPoint p1, QPoint p2, unsigned char color)
243 QPoint ul; // upper-left corner
244 QPoint lr; // lower-right corner
268 int width = lr.x() - ul.x();
269 unsigned long offset = ul.x() + ul.y()*stride;
271 for (int h = ul.y(); h < lr.y(); h++)
273 memset(buf+offset, color, width);
279 * Low-level routines to draw a filled triangle.
281 * The triangle is filled with the given \a color.
282 * The \a stride represents the width of the image buffer (\a buf).
284 * The routine use fixed-point arithmetic.
286 void fillTriangle(unsigned char* buf, unsigned long stride,
287 QPoint v1, QPoint v2, QPoint v3, unsigned char color)
291 // Sort by vertical coordinate
299 altezza[0] = v3.y() - v1.y();
306 buf += v1.y() * stride;
308 altezza[1] = v2.y() - v1.y();
309 altezza[2] = v3.y() - v2.y();
311 int sinistra = v1.x();
312 int destra = sinistra;
314 if (v1.y() == v2.y())
325 int stmp1, stmp2, stmp3;
327 stmp1 = (altezza[1] << 16) / altezza[0];
328 int lunghezza = stmp1 * (v3.x() - v1.x()) + ((v1.x() - v2.x()) << 16);
333 int delta_sinistra[2];
336 stmp1 = ((v3.x() - v1.x()) << 16) / altezza[0];
339 stmp2 = ((v2.x() - v1.x()) << 16) / altezza[1];
341 stmp3 = ((v3.x() - v2.x()) << 16) / altezza[2];
343 if (lunghezza < 0) // Il secondo vertice ~J a destra
345 delta_sinistra[0] = stmp1;
346 delta_sinistra[1] = stmp1;
347 delta_destra[0] = stmp2;
348 delta_destra[1] = stmp3;
350 else // Il secondo vertice ~J a sinistra
352 delta_sinistra[0] = stmp2;
353 delta_sinistra[1] = stmp3;
354 delta_destra[0] = stmp1;
355 delta_destra[1] = stmp1;
358 int len2 = lunghezza;
362 while (altezza [sezione])
364 unsigned char* curpos = buf + ((sinistra )>> 16);
365 lunghezza = ((destra ) >> 16) - ((sinistra ) >> 16);
366 assert(lunghezza >= 0);
368 memset(curpos, color, lunghezza);
370 destra += delta_destra[sezione - 1];
371 sinistra += delta_sinistra[sezione - 1];
375 destra = v2.x() << 16;
377 sinistra = v2.x() << 16;