📄 pw_draw.c
字号:
#include <i_pwin.h>#include "guidebug.h"
/* -------------------------------------------------------------------------- *//** An array of bitmasks. Used for manipulating bits in bitmaps. */const Pw_Byte _bm_edgemask[2][9] = { {0x00, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00}, {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF}};/* -------------------------------------------------------------------------- *//** * Draws a point with clipping. * @param gc pointer to graphic context * @param x point x coord * @param y point y coord * @param clip pointer to clip rectangle * @return true if point is visible (i.e. drawn) * @internal */ static Pw_Bool _DrawClipPoint(Pw_GC* gc, Pw_Coord x, Pw_Coord y, Pw_Rectangle* clip){ IPW_TRACE_ENTER(DR1); IPW_TRACE2(DR1, d, x, y); IPW_TRACE_RECT(DR1, clip); /* * Check if point is inside clip (visible) * and draw it accordingly */ if (IPW_RECT_IS_POINT_IN(x, y, clip)) { gc->d.lld->draw_point(gc, x, y); IPW_TRACE_EXIT_V(DR1, d, TRUE); return(TRUE); } IPW_TRACE_EXIT_V(DR1, d, FALSE); return(FALSE);}/** * Draws a horizontal line with clipping. * @param gc pointer to graphic context * @param x1 start point x coord * @param y1 start point y coord * @param x2 end point x coord * @param clip pointer to clip rectangle * @return true if line is completely visible * @internal */ static Pw_Bool _DrawClipHorLine(Pw_GC* gc, Pw_Coord x1, Pw_Coord y1, Pw_Coord x2, Pw_Rectangle* clip){ IPW_TRACE_ENTER(DR1); IPW_TRACE3(DR1, d, x1, y1, x2); IPW_TRACE_RECT(DR1, clip); /* * First make shure that x1 is smaller than x2 * (flip them if needed). Then check if the line's * y coord is inside the clip rectangle, if y * falls outside the line is not visible at all. * If y falls inside than clip the left side (x1) and * the right side (x2). If there is anything left * of the line - draw it. */ if (x1 > x2) { Pw_Coord t; t = x1; x1 = x2; x2 = t; } if ((y1 >= clip->y) && (y1 < (clip->y + clip->h))) { Pw_Coord cx1 = x1; Pw_Coord cx2 = x2; if (cx1 < clip->x) cx1 = clip->x; if (cx2 >= (clip->x + clip->w)) cx2 = clip->x + clip->w - 1; IPW_TRACE2(DR1, d, cx1, cx2); if (cx1 == x1 && cx2 == x2) { gc->d.lld->draw_hor_line(gc, x1, y1, x2); IPW_TRACE_EXIT_V(DR1, d, TRUE); return(TRUE); } else if (cx1 <= cx2) { gc->d.lld->draw_hor_line(gc, cx1, y1, cx2); IPW_TRACE_EXIT_V(DR1, d, FALSE); return(FALSE); } } IPW_TRACE_EXIT_V(DR1, d, FALSE); return(FALSE);}/** * Draws a vertical line with clipping. * @param gc pointer to graphic context * @param x1 start point x coord * @param y1 start point y coord * @param y2 end point y coord * @param clip pointer to clip rectangle. * @return true if line is completely visible * @internal */ static Pw_Bool _DrawClipVerLine(Pw_GC* gc, Pw_Coord x1, Pw_Coord y1, Pw_Coord y2, Pw_Rectangle* clip){ IPW_TRACE_ENTER(DR1); IPW_TRACE3(DR1, d, x1, y1, y2); IPW_TRACE_RECT(DR1, clip); /* * First make shure that y1 is smaller than y2 * (flip them if needed). Then check if the line's * x coord is inside the clip rectangle, if x * falls outside the line is not visible at all. * If x falls inside than clip the top side (y1) and * the bottom side (y2). If there is anything left * of the line - draw it. */ if (y1 > y2) { Pw_Coord t; t = y1; y1 = y2; y2 = t; } if ((x1 >= clip->x) && (x1 < (clip->x + clip->w))) { Pw_Coord cy1 = y1; Pw_Coord cy2 = y2; if (cy1 < clip->y) cy1 = clip->y; if (cy2 >= (clip->y + clip->h)) cy2 = clip->y + clip->h - 1; IPW_TRACE2(DR1, d, cy1, cy2); if (cy1 == y1 && cy2 == y2) { gc->d.lld->draw_ver_line(gc, x1, y1, y2); IPW_TRACE_EXIT_V(DR1, d, TRUE); return(TRUE); } else if (cy1 <= cy2) { gc->d.lld->draw_ver_line(gc, x1, cy1, cy2); IPW_TRACE_EXIT_V(DR1, d, FALSE); return(FALSE); } } IPW_TRACE_EXIT_V(DR1, d, FALSE); return(FALSE);} /** * Draws a line without clipping. * @param gc pointer to graphic context * @param x1 start point x coord * @param y1 start point y coord * @param x2 end point x coord * @param y2 end point y coord * @internal */ static void _DrawLine(Pw_GC* gc, Pw_Coord x1, Pw_Coord y1, Pw_Coord x2, Pw_Coord y2){ Pw_Int dx, dy; Pw_Int stepx, stepy; IPW_TRACE_ENTER(DR2); IPW_TRACE4(DR2, d, x1, x2, y1, y2); /* Bresenham's line drawing algorithm */ dx = x2 - x1; dy = y2 - y1; if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } dy <<= 1; dx <<= 1; gc->d.lld->draw_point(gc, x1, y1); if (dx > dy) { Pw_Int fraction = dy - (dx >> 1); while (x1 != x2) { if (fraction >= 0) { y1 += stepy; fraction -= dx; } x1 += stepx; fraction += dy; gc->d.lld->draw_point(gc, x1, y1); } } else { Pw_Int fraction = dx - (dy >> 1); while (y1 != y2) { if (fraction >= 0) { x1 += stepx; fraction -= dy; } y1 += stepy; fraction += dx; gc->d.lld->draw_point(gc, x1, y1); } } IPW_TRACE_EXIT(DR2);} /** * Draws a line with clipping. * @param gc pointer to graphic context * @param x1 start point x coord * @param y1 start point y coord * @param x2 end point x coord * @param y2 end point y coord * @param clip pointer to clip rectangle * @todo make this smarter than point to point clipping * @internal */ static void _DrawClipLine(Pw_GC* gc, Pw_Coord x1, Pw_Coord y1, Pw_Coord x2, Pw_Coord y2, Pw_Rectangle* clip){ Pw_Int dx, dy; Pw_Int stepx, stepy; IPW_TRACE_ENTER(DR2); IPW_TRACE4(DR2, d, x1, y1, x2, y2); IPW_TRACE_RECT(DR2, clip); /* Bresenham's line drawing algorithm */ dx = x2 - x1; dy = y2 - y1; if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } dy <<= 1; dx <<= 1; _DrawClipPoint(gc, x1, y1, clip); if (dx > dy) { Pw_Int fraction = dy - (dx >> 1); while (x1 != x2) { if (fraction >= 0) { y1 += stepy; fraction -= dx; } x1 += stepx; fraction += dy; _DrawClipPoint(gc, x1, y1, clip); } } else { Pw_Int fraction = dx - (dy >> 1); while (y1 != y2) { if (fraction >= 0) { x1 += stepx; fraction -= dy; } y1 += stepy; fraction += dx; _DrawClipPoint(gc, x1, y1, clip); } } IPW_TRACE_EXIT(DR2);}/** * Draws an ellipse without clipping. * @param gc pointer to graphic context * @param x ellipse center x coord * @param y ellipse center y coord * @param rx x radius * @param ry y radius * @param fill if true the ellipse will be filled * @internal */ static void _DrawEllipse(Pw_GC* gc, Pw_Coord x, Pw_Coord y, Pw_Coord rx, Pw_Coord ry, Pw_Bool fill){ /* Algorithm from IEEE CG&A Sept 1984 p.24 */ Pw_Long t1 = rx * rx, t2 = t1 << 1, t3 = t2 << 1; Pw_Long t4 = ry * ry, t5 = t4 << 1, t6 = t5 << 1; Pw_Long t7 = rx * t5, t8 = t7 << 1, t9 = 0; Pw_Long d1 = t2 - t7 + (t4 >> 1); Pw_Long d2 = (t1 >> 1) - t8 + t5; Pw_Int ex = rx, ey = 0; IPW_TRACE_ENTER(DR2); IPW_TRACE4(DR2, d, x, y, rx, ry); while (d2 < 0) { if (fill) { gc->d.lld->draw_hor_line(gc, x - ex, y + ey, x + ex); gc->d.lld->draw_hor_line(gc, x - ex, y - ey, x + ex); } else { gc->d.lld->draw_point(gc, x + ex, y + ey); gc->d.lld->draw_point(gc, x + ex, y - ey); gc->d.lld->draw_point(gc, x - ex, y + ey); gc->d.lld->draw_point(gc, x - ex, y - ey); } ey++; t9 += t3; if (d1 < 0) { d1 += t9 + t2; d2 += t9; } else { ex--; t8 -= t6; d1 += t9 + t2 - t8; d2 += t9 + t5 - t8; } } do { if (fill) { gc->d.lld->draw_hor_line(gc, x - ex, y + ey, x + ex); gc->d.lld->draw_hor_line(gc, x - ex, y - ey, x + ex); } else { gc->d.lld->draw_point(gc, x + ex, y + ey); gc->d.lld->draw_point(gc, x + ex, y - ey); gc->d.lld->draw_point(gc, x - ex, y + ey); gc->d.lld->draw_point(gc, x - ex, y - ey); } ex--; t8 -= t6; if (d2 < 0) { ey++; t9 += t3; d2 += t9 + t5 - t8; } else { d2 += t5 - t8; } } while (ex >= 0); IPW_TRACE_EXIT(DR2);}/** * Draws an ellipse with clipping. * @param gc pointer to graphic context * @param x ellipse center x coord * @param y ellipse center y coord * @param rx x radius * @param ry y radius * @param fill if true the ellipse will be filled * @param clip pointer to clip rectangle * @todo make this smarter than point to point clipping * @internal */ static void _DrawClipEllipse(Pw_GC* gc, Pw_Coord x, Pw_Coord y, Pw_Coord rx, Pw_Coord ry, Pw_Bool fill, Pw_Rectangle* clip){ /* Algorithm from IEEE CG&A Sept 1984 p.24 */ Pw_Long t1 = rx * rx, t2 = t1 << 1, t3 = t2 << 1; Pw_Long t4 = ry * ry, t5 = t4 << 1, t6 = t5 << 1; Pw_Long t7 = rx * t5, t8 = t7 << 1, t9 = 0; Pw_Long d1 = t2 - t7 + (t4 >> 1); Pw_Long d2 = (t1 >> 1) - t8 + t5; Pw_Int ex = rx, ey = 0; IPW_TRACE_ENTER(DR2); IPW_TRACE4(DR2, d, x, y, rx, ry); IPW_TRACE_RECT(DR2, clip); while (d2 < 0) { if (fill) { _DrawClipHorLine(gc, x - ex, y + ey, x + ex, clip); _DrawClipHorLine(gc, x - ex, y - ey, x + ex, clip); } else { _DrawClipPoint(gc, x + ex, y + ey, clip); _DrawClipPoint(gc, x + ex, y - ey, clip); _DrawClipPoint(gc, x - ex, y + ey, clip); _DrawClipPoint(gc, x - ex, y - ey, clip); } ey++; t9 += t3; if (d1 < 0) { d1 += t9 + t2; d2 += t9; } else { ex--; t8 -= t6; d1 += t9 + t2 - t8; d2 += t9 + t5 - t8; } } do { if (fill) { _DrawClipHorLine(gc, x - ex, y + ey, x + ex, clip); _DrawClipHorLine(gc, x - ex, y - ey, x + ex, clip); } else { _DrawClipPoint(gc, x + ex, y + ey, clip); _DrawClipPoint(gc, x + ex, y - ey, clip); _DrawClipPoint(gc, x - ex, y + ey, clip); _DrawClipPoint(gc, x - ex, y - ey, clip); } ex--; t8 -= t6; if (d2 < 0) { ey++; t9 += t3; d2 += t9 + t5 - t8; } else { d2 += t5 - t8; } } while (ex >= 0); IPW_TRACE_EXIT(DR2);} /** * Draws a bitmap without clipping. * @param gc pointer to graphic context * @param x x coord of bitmap's top left corner * @param y y coord of bitmap's top left corner * @param w bitmap's width * @param h bitmap's height * @param bits bitmap bits array * @internal */ static void _DrawBitmap(Pw_GC* gc, Pw_Coord x, Pw_Coord y, Pw_Coord w, Pw_Coord h, Pw_Byte* bits) { Pw_uInt i, j; Pw_Coord w8, rx; IPW_TRACE_ENTER(DR2); IPW_TRACE4(DR2, d, x, y, w, h); /* * Calculate bitmap's width in bytes * (bitmap lines end always on byte border - and the unused * bits are just 0) and than draw each byte using draw_points */ w8 = (w + 0x07) >> 3; for (j = 0; j < h; j++) { rx = x; for (i = 0; i < w8; i++) { gc->d.lld->draw_points (gc, rx, y, *bits);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -