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

769 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
*
**********************************************************************
*/
/**
* @brief ????
*
* ????????????????????
*
* @param x0 ?????
* @param y0 ?????
* @param x1 ?????
* @param y1 ?????
*/
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 ****************************/