www.pudn.com > UCGUI390a.rar > GUI2DLib.c


/* 
********************************************************************************************************* 
*                                                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 ****************************/