This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/lib/lcd/gui/Core/GUI2DLib.c

690 lines
16 KiB
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 <stddef.h> /* 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 ****************************/