summaryrefslogtreecommitdiff
path: root/rtgui
diff options
context:
space:
mode:
authorbernard.xiong <[email protected]>2009-10-26 05:25:51 +0000
committerbernard.xiong <[email protected]>2009-10-26 05:25:51 +0000
commit3c41a849a88e651ed4bcf3b1c4015382ddfd82f2 (patch)
treed6baf9311609fb9c4ea761921c014e6e202162ec /rtgui
parent49a0ca309d2bcbecab1a8e4e208ea04f75f68668 (diff)
add rtgui_dc_draw_arc function.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@139 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'rtgui')
-rw-r--r--rtgui/common/dc.c436
1 files changed, 225 insertions, 211 deletions
diff --git a/rtgui/common/dc.c b/rtgui/common/dc.c
index 0ccd51ebfa..d1b819d12c 100644
--- a/rtgui/common/dc.c
+++ b/rtgui/common/dc.c
@@ -17,6 +17,12 @@
#include <string.h> /* for strlen */
#include <stdlib.h> /* fir qsort */
+/* for sin/cos etc */
+#include <math.h>
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
void rtgui_dc_destory(struct rtgui_dc* dc)
{
if (dc == RT_NULL) return;
@@ -35,24 +41,6 @@ void rtgui_dc_draw_point(struct rtgui_dc* dc, int x, int y)
dc->draw_point(dc, x, y);
}
-#if 0
-void rtgui_dc_draw_point_alpha(struct rtgui_dc* dc, int x, int y, rt_uint8_t alpha)
-{
- if (dc == RT_NULL || alpha == 0xff) return;
-
- if (dc->draw_point_alpha != RT_NULL)
- dc->draw_point_alpha(dc, x, y, alpha);
- else
- {
- rtgui_color_t color;
-
- /* soft alpha bending */
- color = dc->get_color(dc, int x, int y);
- dc->draw_point(dc, x, y);
- }
-}
-#endif
-
/*
* draw a vertical line on dc
*/
@@ -141,199 +129,6 @@ void rtgui_dc_draw_line (struct rtgui_dc* dc, int x1, int y1, int x2, int y2)
}
}
-#if 0
-/* AA Line */
-#define AAlevels 256
-#define AAbits 8
-
-int rtgui_dc_draw_line_aa(struct rtgui_dc* dc, rt_int16_t x1, rt_int16_t y1, rt_int16_t x2, rt_int16_t y2)
-{
- Sint32 xx0, yy0, xx1, yy1;
- int result;
- rt_uint32_t intshift, erracc, erradj;
- rt_uint32_t erracctmp, wgt, wgtcompmask;
- int dx, dy, tmp, xdir, y0p1, x0pxdir;
-
- /*
- * Keep on working with 32bit numbers
- */
- xx0 = x1;
- yy0 = y1;
- xx1 = x2;
- yy1 = y2;
-
- /*
- * Reorder points if required
- */
- if (yy0 > yy1)
- {
- tmp = yy0;
- yy0 = yy1;
- yy1 = tmp;
- tmp = xx0;
- xx0 = xx1;
- xx1 = tmp;
- }
-
- /*
- * Calculate distance
- */
- dx = xx1 - xx0;
- dy = yy1 - yy0;
-
- /*
- * Adjust for negative dx and set xdir
- */
- if (dx >= 0)
- {
- xdir = 1;
- }
- else
- {
- xdir = -1;
- dx = (-dx);
- }
-
- /*
- * Check for special cases
- */
- if (dx == 0)
- {
- /*
- * Vertical line
- */
- rtgui_dc_draw_vline(dc, x1, y1, y2);
- return ;
- }
- else if (dy == 0)
- {
- /*
- * Horizontal line
- */
- rtgui_dc_draw_hline(dc, x1, x2, y1);
- return ;
- }
- else if (dx == dy)
- {
- /*
- * Diagonal line
- */
- rtgui_dc_draw_line(dc, x1, y1, x2, y2);
- return ;
- }
-
- /*
- * Zero accumulator
- */
- erracc = 0;
-
- /*
- * # of bits by which to shift erracc to get intensity level
- */
- intshift = 32 - AAbits;
- /*
- * Mask used to flip all bits in an intensity weighting
- */
- wgtcompmask = AAlevels - 1;
-
- /*
- * Draw the initial pixel in the foreground color
- */
- rtgui_dc_draw_point(dc, x1, y1);
-
- /*
- * x-major or y-major?
- */
- if (dy > dx)
- {
- /*
- * y-major. Calculate 16-bit fixed point fractional part of a pixel that
- * X advances every time Y advances 1 pixel, truncating the result so that
- * we won't overrun the endpoint along the X axis
- */
- /*
- * Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
- */
- erradj = ((dx << 16) / dy) << 16;
-
- /*
- * draw all pixels other than the first and last
- */
- x0pxdir = xx0 + xdir;
- while (--dy)
- {
- erracctmp = erracc;
- erracc += erradj;
- if (erracc <= erracctmp)
- {
- /*
- * rollover in error accumulator, x coord advances
- */
- xx0 = x0pxdir;
- x0pxdir += xdir;
- }
- yy0++; /* y-major so always advance Y */
-
- /*
- * the AAbits most significant bits of erracc give us the intensity
- * weighting for this pixel, and the complement of the weighting for
- * the paired pixel.
- */
- wgt = (erracc >> intshift) & 255;
- rtgui_dc_draw_point_alpha (dc, xx0, yy0, 255 - wgt);
- rtgui_dc_draw_point_alpha (dc, x0pxdir, yy0, wgt);
- }
- }
- else
- {
-
- /*
- * x-major line. Calculate 16-bit fixed-point fractional part of a pixel
- * that Y advances each time X advances 1 pixel, truncating the result so
- * that we won't overrun the endpoint along the X axis.
- */
- /*
- * Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
- */
- erradj = ((dy << 16) / dx) << 16;
-
- /*
- * draw all pixels other than the first and last
- */
- y0p1 = yy0 + 1;
- while (--dx)
- {
-
- erracctmp = erracc;
- erracc += erradj;
- if (erracc <= erracctmp)
- {
- /*
- * Accumulator turned over, advance y
- */
- yy0 = y0p1;
- y0p1++;
- }
- xx0 += xdir; /* x-major so always advance X */
- /*
- * the AAbits most significant bits of erracc give us the intensity
- * weighting for this pixel, and the complement of the weighting for
- * the paired pixel.
- */
- wgt = (erracc >> intshift) & 255;
- rtgui_dc_draw_point_alpha (dc, xx0, yy0, 255 - wgt);
- rtgui_dc_draw_point_alpha (dc, xx0, y0p1, wgt);
- }
- }
-
- /*
- * Draw final pixel, always exactly intersected by the line and doesn't
- * need to be weighted.
- */
- rtgui_dc_draw_point(dc, x2, y2);
-}
-#endif
-
void rtgui_dc_draw_rect (struct rtgui_dc* dc, struct rtgui_rect* rect)
{
rtgui_dc_draw_hline(dc, rect->x1, rect->x2, rect->y1);
@@ -944,6 +739,225 @@ void rtgui_dc_fill_circle(struct rtgui_dc* dc, rt_int16_t x, rt_int16_t y, rt_in
} while (cx <= cy);
}
+void rtgui_dc_draw_arc(struct rtgui_dc *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r, rt_int16_t start, rt_int16_t end)
+{
+ rt_int16_t cx = 0;
+ rt_int16_t cy = r;
+ rt_int16_t ocx = (rt_int16_t) 0xffff;
+ rt_int16_t ocy = (rt_int16_t) 0xffff;
+ rt_int16_t df = 1 - r;
+ rt_int16_t d_e = 3;
+ rt_int16_t d_se = -2 * r + 5;
+ rt_int16_t xpcx, xmcx, xpcy, xmcy;
+ rt_int16_t ypcy, ymcy, ypcx, ymcx;
+ rt_uint8_t drawoct;
+ int startoct, endoct, oct, stopval_start, stopval_end;
+ double temp;
+
+ /* Sanity check radius */
+ if (r < 0) return ;
+ /* Special case for r=0 - draw a point */
+ if (r == 0)
+ {
+ rtgui_dc_draw_point(dc, x, y);
+ return;
+ }
+
+ /* Fixup angles */
+ start = start % 360;
+ end = end % 360;
+
+ /*
+ * Draw arc
+ */
+
+ // Octant labelling
+ //
+ // \ 5 | 6 /
+ // \ | /
+ // 4 \ | / 7
+ // \|/
+ //------+------ +x
+ // /|\
+ // 3 / | \ 0
+ // / | \
+ // / 2 | 1 \
+ // +y
+
+ drawoct = 0; // 0x00000000
+ // whether or not to keep drawing a given octant.
+ // For example: 0x00111100 means we're drawing in octants 2-5
+
+ // 0 <= start & end < 360; note that sometimes start > end - if so, arc goes back through 0.
+ while (start < 0) start += 360;
+ while (end < 0) end += 360;
+ start %= 360;
+ end %= 360;
+
+ // now, we find which octants we're drawing in.
+ startoct = start / 45;
+ endoct = end / 45;
+ oct = startoct - 1; // we increment as first step in loop
+
+ //stopval_start, stopval_end; // what values of cx to stop at.
+ do {
+ oct = (oct + 1) % 8;
+
+ if (oct == startoct)
+ {
+ // need to compute stopval_start for this octant. Look at picture above if this is unclear
+ switch (oct)
+ {
+ case 0:
+ case 3:
+ temp = sin(start * M_PI / 180);
+ break;
+ case 1:
+ case 6:
+ temp = cos(start * M_PI / 180);
+ break;
+ case 2:
+ case 5:
+ temp = -cos(start * M_PI / 180);
+ break;
+ case 4:
+ case 7:
+ temp = -sin(start * M_PI / 180);
+ break;
+ }
+ temp *= r;
+ stopval_start = (int)temp; // always round down.
+ // This isn't arbitrary, but requires graph paper to explain well.
+ // The basic idea is that we're always changing drawoct after we draw, so we
+ // stop immediately after we render the last sensible pixel at x = ((int)temp).
+
+ // and whether to draw in this octant initially
+ if (oct % 2) drawoct |= (1 << oct); // this is basically like saying drawoct[oct] = true, if drawoct were a bool array
+ else drawoct &= 255 - (1 << oct); // this is basically like saying drawoct[oct] = false
+ }
+
+ if (oct == endoct)
+ {
+ // need to compute stopval_end for this octant
+ switch (oct)
+ {
+ case 0:
+ case 3:
+ temp = sin(end * M_PI / 180);
+ break;
+ case 1:
+ case 6:
+ temp = cos(end * M_PI / 180);
+ break;
+ case 2:
+ case 5:
+ temp = -cos(end * M_PI / 180);
+ break;
+ case 4:
+ case 7:
+ temp = -sin(end * M_PI / 180);
+ break;
+ }
+ temp *= r;
+ stopval_end = (int)temp;
+
+ // and whether to draw in this octant initially
+ if (startoct == endoct)
+ {
+ // note: we start drawing, stop, then start again in this case
+ // otherwise: we only draw in this octant, so initialize it to false, it will get set back to true
+ if (start > end)
+ {
+ // unfortunately, if we're in the same octant and need to draw over the whole circle,
+ // we need to set the rest to true, because the while loop will end at the bottom.
+ drawoct = 255;
+ }
+ else
+ {
+ drawoct &= 255 - (1 << oct);
+ }
+ }
+ else if (oct % 2) drawoct &= 255 - (1 << oct);
+ else drawoct |= (1 << oct);
+ } else if (oct != startoct) { // already verified that it's != endoct
+ drawoct |= (1 << oct); // draw this entire segment
+ }
+ } while (oct != endoct);
+
+ // so now we have what octants to draw and when to draw them. all that's left is the actual raster code.
+ do
+ {
+ ypcy = y + cy;
+ ymcy = y - cy;
+ if (cx > 0)
+ {
+ xpcx = x + cx;
+ xmcx = x - cx;
+ // always check if we're drawing a certain octant before adding a pixel to that octant.
+ if (drawoct & 4) rtgui_dc_draw_point(dc, xmcx, ypcy); // drawoct & 4 = 22; drawoct[2]
+ if (drawoct & 2) rtgui_dc_draw_point(dc, xpcx, ypcy);
+ if (drawoct & 32) rtgui_dc_draw_point(dc, xmcx, ymcy);
+ if (drawoct & 64) rtgui_dc_draw_point(dc, xpcx, ymcy);
+ }
+ else
+ {
+ if (drawoct & 6) rtgui_dc_draw_point(dc, x, ypcy); // 4 + 2; drawoct[2] || drawoct[1]
+ if (drawoct & 96) rtgui_dc_draw_point(dc, x, ymcy); // 32 + 64
+ }
+
+ xpcy = x + cy;
+ xmcy = x - cy;
+ if (cx > 0 && cx != cy)
+ {
+ ypcx = y + cx;
+ ymcx = y - cx;
+ if (drawoct & 8) rtgui_dc_draw_point(dc, xmcy, ypcx);
+ if (drawoct & 1) rtgui_dc_draw_point(dc, xpcy, ypcx);
+ if (drawoct & 16) rtgui_dc_draw_point(dc, xmcy, ymcx);
+ if (drawoct & 128) rtgui_dc_draw_point(dc, xpcy, ymcx);
+ }
+ else if (cx == 0)
+ {
+ if (drawoct & 24) rtgui_dc_draw_point(dc, xmcy, y); // 8 + 16
+ if (drawoct & 129) rtgui_dc_draw_point(dc, xpcy, y); // 1 + 128
+ }
+
+ /*
+ * Update whether we're drawing an octant
+ */
+ if (stopval_start == cx)
+ {
+ // works like an on-off switch because start & end may be in the same octant.
+ if (drawoct & (1 << startoct)) drawoct &= 255 - (1 << startoct);
+ else drawoct |= (1 << startoct);
+ }
+ if (stopval_end == cx)
+ {
+ if (drawoct & (1 << endoct)) drawoct &= 255 - (1 << endoct);
+ else drawoct |= (1 << endoct);
+ }
+
+ /*
+ * Update pixels
+ */
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+
+ cx++;
+ } while (cx <= cy);
+}
+
void rtgui_dc_draw_ellipse(struct rtgui_dc* dc, rt_int16_t x, rt_int16_t y, rt_int16_t rx, rt_int16_t ry)
{
int ix, iy;