/* ********************************************************************************************************* * uC/GUI * Universal graphic software for embedded applications * * (c) Copyright 2002, Micrium Inc., Weston, FL * (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH * * µC/GUI is protected by international copyright laws. Knowledge of the * source code may not be used to write a similar product. This file may * only be used in accordance with a license and should not be redistributed * in any way. We appreciate your understanding and fairness. * ---------------------------------------------------------------------- File : GUI2DLib.C Purpose : Main part of the 2D graphics library ---------------------------END-OF-HEADER------------------------------ */ #include /* needed for definition of NULL */ #include "GUI_Protected.h" #include "GUIDebug.h" /********************************************************************* * * defines * ********************************************************************** */ #define ABS(v) ((v>0) ? v : -v) /********************************************************************* * * static code, helper functions * ********************************************************************** */ /********************************************************************* * * _SwapInt */ static void _SwapInt(int* pa, int* pb) { int t; t = *pa; *pa = *pb; *pb = t; } /********************************************************************* * * Abs */ static int Abs(int v) { return ABS(v); } /********************************************************************* * * trigonometric functions * * NOTE: * All trigonometric functions are for internal usage only and * use the following conventions: * * Angles: 4096 <==> 360° * ********************************************************************** */ #if GUI_45DEG != 512 #error Wrong define for this library ! #endif /********************************************************************* * * sin / cos (internal) * * Angle : 90/1024° * Data : 1/1024 */ static const U16 aSin[] = { 0, /* 1/16 *90° */ 100, /* 1/16 *90° */ 200, /* 2/16 *90° */ 297, /* 3/16 *90° */ 392, /* 4/16 *90° */ 483, /* 5/16 *90° */ 569, /* 6/16 *90° */ 650, /* 7/16 *90° */ 724, /* 8/16 *90° */ 792, /* 9/16 *90° */ 851, /* 10/16 *90° */ 903, /* 11/16 *90° */ 946, /* 12/16 *90° */ 980, /* 13/16 *90° */ 1004, /* 14/16 *90° */ 1019, /* 15/16 *90° */ 1024 /* 16/16 *90° */ }; /********************************************************************* * * GUI_sin */ int GUI_sin(int angle) { char IsNeg =0; int i; U16 Faktor; U32 t; angle &= ((1<<12)-1); /* reduce to 0-360 degrees */ if (angle> 2* GUI_90DEG) { angle -= 2* GUI_90DEG; IsNeg =1; } if (angle> GUI_90DEG) { /* between 90-180 */ angle = 2*GUI_90DEG-angle; /* use sine symetry */ } /* Now angle is reduced to 0° <= <= 90° */ #if 0 angle >>=2; /* make sure we do not exceed 16 bits in calculations */ i = angle>>4; Faktor = (1<<4)-(angle&((1<<4)-1)); r = aSin[i]*Faktor; if (Faktor !=(1<<4)) { r += aSin[i+1]*((1<<4)-Faktor); } r = (r+(1<<3)) >>4; /* divide,incl. rounding */ #else i = angle>>6; { Faktor = (U16)((1<<6)-(angle&((1<<6)-1))); t = aSin[i]*(U32)Faktor; if (Faktor !=(1<<6)) { t += aSin[i+1]*((1<<6)-Faktor); } } t = (t+(1<<5)) >>6; /* divide,incl. rounding */ #endif return (IsNeg) ? 0-t : t; } /********************************************************************* * * GUI_cos */ int GUI_cos(int angle) { return GUI_sin(angle+GUI_90DEG); } /********************************************************************* * * atan() (internal) * * Angle : 360/4096° */ const I16 aTan[] = { 0, /* atan(0/16) */ 41, /* atan(1/16) */ 81, /* atan(2/16) */ 121, /* atan(3/16) */ 160, /* atan(4/16) */ 197, /* atan(5/16) */ 234, /* atan(6/16) */ 269, /* atan(7/16) */ 302, /* atan(8/16) */ 334, /* atan(9/16) */ 364, /* atan(10/16) */ 393, /* atan(11/16) */ 419, /* atan(12/16) */ 445, /* atan(13/16) */ 469, /* atan(14/16) */ 491, /* atan(15/16) */ 512 /* atan(1) = 45° = 512/1024 */ }; /********************************************************************* * * _atan0_45 * * Calculate arctan of q, where q is any where between 0 and 1024 */ static int _atan0_45(int q) { int r; int i, Faktor; /* Now angle is reduced to 0° <= <= 90° ==> 0 <= <= 256*/ q >>=2; /* make sure we do not exceed 16 bits in calculations */ i = q>>4; Faktor = (1<<4)-(q&((1<<4)-1)); r = aTan[i]*Faktor; if (Faktor !=(1<<4)) { r += aTan[i+1]*((1<<4)-Faktor); } r = (r+(1<<3))/(1<<4); /* divide incl. rounding */ return r; } /********************************************************************* * * _atan2 */ static int _atan2(I32 x, I32 y) { U8 q =0; int angle; /* first make sure we are in angle between 0 and 45° */ if (x<0) { q=1; x=-x; } if (y<0) { q |= (1<<1); y=-y; } if (y>x) { int t = y; y=x; x=t; q |= (1<<2); } y <<=10; y += (x/2); y /= x; angle = _atan0_45(y); if (q&(1<<2)) { /* y/x reverse ? */ angle = GUI_90DEG-angle; } if (q&1) { /* xreverse ? */ angle = GUI_180DEG-angle; } if (q&(1<<1)) { /* y-reverse ? */ angle = GUI_360DEG-angle; } return angle; } /********************************************************************* * * _SetLineColor */ static int _SetLineColor(int i) { switch (GUI_Context.LineStyle) { case GUI_LS_DASH: i = (i+6)%16; return (i<12); case GUI_LS_DOT: i %= 4; return (i<2); case GUI_LS_DASHDOT: i %= 20; if (i<12) return 1; else if ((i>=16) && (i<18)) return 1; return 0; case GUI_LS_DASHDOTDOT: i %= 24; if (i<12) return 1; else if ((i>=16) && (i<18)) return 1; else if ((i>=20) && (i<22)) return 1; else return 0; } return 0; } /********************************************************************* * * _atan2 */ #if 0 int _atan2(int xDiff, int yDiff) { double atanf = atan2(xDiff, yDiff); return (int)(atanf*(16384.0/6.2831852)); } #endif /********************************************************************* * * _CalcOrto */ static void _CalcOrto(int xDiff, int yDiff, I32 r, int*px, int*py) { I32 x,y; /* int Angle = _atan2(xDiff, yDiff); */ #if 0 double Angle = atan2(xDiff, yDiff); x = (int)(-r*cos(Angle)); y = (int)(r*sin(Angle)); #else int Angle = _atan2(xDiff, yDiff); Angle+= GUI_90DEG; x = ( r*(I32)GUI_cos(Angle)); y = ( r*(I32)GUI_sin(Angle)); #endif x = (x<0) ? -((-x+512)>>10) : ((x+512)>>10); y = (y<0) ? -((-y+512)>>10) : ((y+512)>>10); *px = x; *py = y; } /********************************************************************* * * DrawLine, public * * Draw end points of the line. * In most cases, this is a circle. * ********************************************************************** */ /********************************************************************* * * _DrawLineEnd */ static void _DrawLineEnd(int x0, int y0) { switch (GUI_Context.PenShape) { case GUI_PS_ROUND: GL_DrawPoint(x0,y0); break; case GUI_PS_FLAT: break; } } /********************************************************************* * * DrawLine, public * ********************************************************************** */ /********************************************************************* * * GL_DrawLine */ void GL_DrawLine(int x0, int y0, int x1, int y1) { if (GUI_Context.PenSize ==1) { GL_DrawLine1(x0,y0,x1,y1); } else { int xdiff, ydiff; xdiff = x0-x1; ydiff = y0-y1; if (xdiff | ydiff) { GUI_POINT Poly[4]; int xOff, yOff; int xOffP, yOffP, xOffM, yOffM; _CalcOrto(x0-x1,y0-y1, (I32)(GUI_Context.PenSize-1), &xOff, &yOff); /* Do rounding for offsets */ if (xOff >0) { xOffP = (xOff+1)/2; xOffM = xOff /2; } else { xOffP = xOff/2; xOffM = (xOff-1) /2; } if (yOff >0) { yOffP = (yOff+1)/2; yOffM = yOff /2; } else { yOffP = yOff/2; yOffM = (yOff-1) /2; } Poly[0].x = x0+xOffP; Poly[0].y = y0+yOffP; Poly[1].x = x0-xOffM; Poly[1].y = y0-yOffM; Poly[2].x = x1-xOffM; Poly[2].y = y1-yOffM; Poly[3].x = x1+xOffP; Poly[3].y = y1+yOffP; GL_FillPolygon(&Poly[0], 4, 0,0); _DrawLineEnd(x0,y0); _DrawLineEnd(x1,y1); } } } /********************************************************************* * * GUI_DrawLine */ void GUI_DrawLine(int x0, int y0, int x1, int y1) { GUI_LOCK(); #if (GUI_WINSUPPORT) WM_ADDORG(x0,y0); WM_ADDORG(x1,y1); WM_ITERATE_START(NULL); { #endif GL_DrawLine (x0, y0, x1, y1); #if (GUI_WINSUPPORT) } WM_ITERATE_END(); #endif GUI_UNLOCK(); } /********************************************************************* * * GL_DrawPolygon */ void GL_DrawPolygon(const GUI_POINT*pPoints, int NumPoints, int x0, int y0) { const GUI_POINT* pPoint = pPoints; GL_MoveTo(pPoint->x+x0, pPoint->y+y0); while (--NumPoints >0) { pPoint++; GL_DrawLineTo(pPoint->x+x0, pPoint->y+y0); } /* Now draw closing line unless it has already been closed */ if ( (pPoint->x != pPoints->x) ||(pPoint->y != pPoints->y)) { GL_DrawLineTo(pPoints->x+x0, pPoints->y+y0); } } /********************************************************************* * * GUI_DrawPolygon */ void GUI_DrawPolygon(const GUI_POINT* pPoints, int NumPoints, int x0, int y0) { GUI_LOCK(); #if (GUI_WINSUPPORT) WM_ADDORG(x0,y0); WM_ITERATE_START(NULL); { #endif GL_DrawPolygon (pPoints, NumPoints, x0, y0); #if (GUI_WINSUPPORT) } WM_ITERATE_END(); #endif GUI_UNLOCK(); } /********************************************************************* * * Draw Line to group * ********************************************************************** */ /********************************************************************* * * GL_DrawLineRelNM */ static void GL_DrawLineRelNM(int dx, int dy) { GL_DrawLine (GUI_Context.DrawPosX, GUI_Context.DrawPosY, GUI_Context.DrawPosX+dx, GUI_Context.DrawPosY+dy); } /********************************************************************* * * GUI_DrawLineRel */ void GUI_DrawLineRel(int dx, int dy) { GUI_LOCK(); #if (GUI_WINSUPPORT) WM_ITERATE_START(NULL); { #endif GL_DrawLineRelNM(dx,dy); #if (GUI_WINSUPPORT) } WM_ITERATE_END(); #endif GUI_MoveRel(dx,dy); GUI_UNLOCK(); } /********************************************************************* * * GL_DrawLineTo */ void GL_DrawLineTo(int x, int y) { GL_DrawLine (GUI_Context.DrawPosX, GUI_Context.DrawPosY, x, y); GUI_Context.DrawPosX = x; GUI_Context.DrawPosY = y; } /********************************************************************* * * GL_DrawLineToNM */ static void GL_DrawLineToNM(int x, int y) { GL_DrawLine (GUI_Context.DrawPosX, GUI_Context.DrawPosY, x, y); } /********************************************************************* * * GUI_DrawLineTo */ void GUI_DrawLineTo(int x, int y) { GUI_LOCK(); #if (GUI_WINSUPPORT) WM_ADDORG(x,y); WM_ITERATE_START(NULL); { #endif GL_DrawLineToNM(x,y); #if (GUI_WINSUPPORT) } WM_ITERATE_END(); #endif GL_MoveTo(x,y); GUI_UNLOCK(); } /********************************************************************* * * GUI_MoveRel */ void GUI_MoveRel(int dx, int dy) { /*tbd: GL_LinePos. */ GUI_LOCK(); GUI_Context.DrawPosX += dx; GUI_Context.DrawPosY += dy; GUI_UNLOCK(); } /********************************************************************* * * GL_MoveTo */ void GL_MoveTo(int x, int y) { GUI_Context.DrawPosX = x; GUI_Context.DrawPosY = y; } /********************************************************************* * * GUI_MoveTo */ void GUI_MoveTo(int x, int y) { GUI_LOCK(); #if (GUI_WINSUPPORT) WM_ADDORG(x,y); #endif GL_MoveTo(x,y); GUI_UNLOCK(); } /********************************************************************* * * Rectangle filling / inverting * ********************************************************************** */ /********************************************************************* * * _DrawRect */ static void _DrawRect(int x0, int y0, int x1, int y1) { LCD_DrawHLine(x0, y0, x1); LCD_DrawHLine(x0, y1, x1); LCD_DrawVLine(x0, y0 + 1, y1 - 1); LCD_DrawVLine(x1, y0 + 1, y1 - 1); } /********************************************************************* * * GUI_DrawRect */ void GUI_DrawRect(int x0, int y0, int x1, int y1) { #if (GUI_WINSUPPORT) int Off; GUI_RECT r; #endif GUI_LOCK(); #if (GUI_WINSUPPORT) Off = GUI_Context.PenSize -1; WM_ADDORG(x0,y0); WM_ADDORG(x1,y1); r.x0 = x0 - Off; r.x1 = x1 + Off; r.y0 = y0 - Off; r.y1 = y1 + Off; WM_ITERATE_START(&r); { #endif _DrawRect(x0, y0, x1, y1); #if (GUI_WINSUPPORT) } WM_ITERATE_END(); #endif GUI_UNLOCK(); } /********************************************************************* * * DrawLine, internal, 1 pixel * ********************************************************************** */ /********************************************************************* * * GL_DrawLine1 */ void GL_DrawLine1(int x0, int y0, int x1, int y1) { int xdiff = x1-x0; int ydiff = y1-y0; int xdiffby2; int i; char Swapped =0; /* check if no line */ if (!(xdiff|ydiff)) { GL_DrawPoint(x0,y0); return; } #if 0 /* check if horizontal line */ if (!xdiff) { GL_DrawVLine(x0,y0,y1); return; } /* check if vertical line */ if (!ydiff) { GL_DrawHLine(y0,x0,x1); return; } #endif /* check if we swap x and y for calculation */ if (Abs(xdiff) < Abs(ydiff)) { _SwapInt(&xdiff,&ydiff); _SwapInt(&x0,&y0); _SwapInt(&x1,&y1); Swapped =1; } /* make sure line direction is positive */ if (xdiff!=Abs(xdiff)) { xdiff = -xdiff; ydiff = -ydiff; _SwapInt(&x0,&x1); _SwapInt(&y0,&y1); } xdiffby2 = xdiff/2; if (ydiff<0) xdiffby2 = -xdiffby2; /* Draw pixel by pixel solid*/ if (GUI_Context.LineStyle == GUI_LS_SOLID) { for (i=0; i<=xdiff; i++) { I32 l = ((I32)ydiff)*i+xdiffby2; int y = (ABS(l)<32767) ? (y0 + ((int)l)/xdiff) : (y0 + l/xdiff); if (!Swapped) LCD_HL_DrawPixel(x0+i, y); else LCD_HL_DrawPixel(y, x0+i); } /* Draw pixel by pixel with fill style */ } else { for (i=0; i<=xdiff; i++) { long l = ((long)ydiff)*i+xdiffby2; int y = (ABS(l)<32767) ? (y0 + ((int)l)/xdiff) : (y0 + l/xdiff); if (!_SetLineColor(i)) { if (!Swapped) LCD_HL_DrawPixel(x0+i, y); else LCD_HL_DrawPixel(y, x0+i); } } } } /********************************************************************* * * Draw point * ********************************************************************** */ /********************************************************************* * * GL_DrawPoint */ void GL_DrawPoint(int x, int y) { if (GUI_Context.PenSize == 1) { LCD_HL_DrawPixel(x, y); } else { GL_FillCircle(x, y, (GUI_Context.PenSize - 1) / 2); } } /********************************************************************* * * GUI_DrawPoint */ void GUI_DrawPoint(int x, int y) { GUI_LOCK(); #if (GUI_WINSUPPORT) WM_ADDORG(x, y); WM_ITERATE_START(NULL); { #endif GL_DrawPoint(x, y); #if (GUI_WINSUPPORT) } WM_ITERATE_END(); #endif GUI_UNLOCK(); } /*************************** End of file ****************************/