/* ---------------------------------------------------------------------------- | |
* SAM Software Package License | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2011, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/** \addtogroup lcdd_draw | |
* | |
* Implementation of draw function on LCD, Include draw text, image | |
* and basic shapes (line, rectangle, circle). | |
* | |
*/ | |
/** \file */ | |
/*---------------------------------------------------------------------------- | |
* Headers | |
*----------------------------------------------------------------------------*/ | |
#include "board.h" | |
#include <stdint.h> | |
#include <string.h> | |
#include <assert.h> | |
/*---------------------------------------------------------------------------- | |
* Local variable | |
*----------------------------------------------------------------------------*/ | |
/** Front color cache */ | |
static uint32_t dwFrontColor; | |
/*---------------------------------------------------------------------------- | |
* Local functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* Hide canvas layer | |
*/ | |
static void _HideCanvas(void) | |
{ | |
//LCDD_EnableLayer(LCDD_GetCanvas()->bLayer, 0); | |
} | |
/** | |
* Update canvas | |
*/ | |
static void _ShowCanvas(void) | |
{ | |
//LCDD_EnableLayer(LCDD_GetCanvas()->bLayer, 1); | |
} | |
/** | |
* Set front color | |
* \param dwColor Pixel color. | |
*/ | |
static void _SetFrontColor(uint32_t dwColor) | |
{ | |
dwFrontColor = dwColor; | |
} | |
/** | |
* \brief Draw a pixel on LCD of front color. | |
* | |
* \param dwX X-coordinate of pixel. | |
* \param dwY Y-coordinate of pixel. | |
*/ | |
static void _DrawPixel( uint32_t dwX, uint32_t dwY ) | |
{ | |
sLCDDLayer *pDisp = LCDD_GetCanvas(); | |
uint8_t* buffer = pDisp->pBuffer; | |
uint16_t w = pDisp->wImgW; | |
//uint16_t h = pDisp->wImgH; | |
uint16_t cw = pDisp->bMode/8; /* color width */ | |
uint32_t rw = w * cw; /* row width in bytes */ | |
//uint8_t r, g, b; | |
uint8_t *pPix; | |
if (buffer == NULL) | |
return; | |
if (rw & 0x3) rw = (rw | 0x3) + 1; /* 4-byte aligned rows */ | |
pPix = &buffer[dwY * rw + cw * dwX]; | |
switch (pDisp->bMode) | |
{ | |
case 16: /* TRGB 1555 */ | |
pPix[0] = (dwFrontColor ) & 0xFF; | |
pPix[1] = (dwFrontColor >> 8) & 0xFF; | |
break; | |
case 24: /* RGB 888 */ | |
pPix[0] = (dwFrontColor ) & 0xFF; | |
pPix[1] = (dwFrontColor >> 8) & 0xFF; | |
pPix[2] = (dwFrontColor >> 16) & 0xFF; | |
break; | |
case 32: /* ARGB 8888 */ | |
pPix[0] = (dwFrontColor ) & 0xFF; | |
pPix[1] = (dwFrontColor >> 8) & 0xFF; | |
pPix[2] = (dwFrontColor >> 16) & 0xFF; | |
pPix[3] = (dwFrontColor >> 24) & 0xFF; | |
break; | |
} | |
} | |
/** | |
* \brief Fill rectangle with front color. | |
* \param dwX1 X-coordinate of top left. | |
* \param dwY1 Y-coordinate of top left. | |
* \param dwX2 X-coordinate of bottom right. | |
* \param dwY1 Y-coordinate of bottom right. | |
*/ | |
static void _FillRect( uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2 ) | |
{ | |
sLCDDLayer *pDisp = LCDD_GetCanvas(); | |
uint16_t w = pDisp->wImgW; | |
uint16_t cw = pDisp->bMode/8; /* color width */ | |
uint32_t rw = w * cw; /* row width in bytes */ | |
uint8_t *base = pDisp->pBuffer; | |
uint8_t *buffer = pDisp->pBuffer; | |
uint32_t fillStart, fillEnd; | |
uint32_t i; | |
if (buffer == NULL) return; | |
/* 4-byte aligned rows */ | |
if (rw & 0x3) rw = (rw | 0x3) + 1; | |
/* Buffer address for the starting row */ | |
base = &buffer[dwY1*rw]; | |
fillStart = dwX1 * cw; | |
fillEnd = dwX2 * cw; | |
#if 1 /* Memcopy pixel */ | |
buffer = base; | |
for (; dwY1 <= dwY2; dwY1 ++) | |
{ | |
for (i = fillStart; i <= fillEnd; i += cw) | |
{ | |
memcpy(&buffer[i], &dwFrontColor, cw); | |
} | |
buffer = &buffer[rw]; | |
} | |
#endif | |
#if 0 /* Pixel by pixel */ | |
for (; dwY1 <= dwY2; dwY1 ++) | |
{ | |
for (i = dwX1; i <= dwX2; i ++) | |
{ | |
_DrawPixel(i, dwY1); | |
} | |
} | |
#endif | |
#if 0 /* Optimized */ | |
/* First row */ | |
for (i = fillStart; i <= fillEnd; i += cw) | |
{ | |
memcpy(&base[i], &dwFrontColor, cw); | |
} | |
/* Next rows, copy first */ | |
buffer = &base[rw + fillStart]; | |
for (i = dwY1 + 1; i <= dwY2; i ++) | |
{ | |
memcpy(buffer, &base[fillStart], fillEnd - fillStart + cw); | |
buffer = &buffer[rw]; | |
} | |
#endif | |
} | |
/** | |
* \brief Draw a line on LCD, which is not horizontal or vertical. | |
* | |
* \param dwX1 X-coordinate of line start. | |
* \param dwY1 Y-coordinate of line start. | |
* \param dwX2 X-coordinate of line end. | |
* \param dwY2 Y-coordinate of line end. | |
*/ | |
static uint32_t _DrawLineBresenham( uint32_t dwX1, uint32_t dwY1, | |
uint32_t dwX2, uint32_t dwY2 ) | |
{ | |
int dx, dy ; | |
int i ; | |
int xinc, yinc, cumul ; | |
int x, y ; | |
x = dwX1 ; | |
y = dwY1 ; | |
dx = dwX2 - dwX1 ; | |
dy = dwY2 - dwY1 ; | |
xinc = ( dx > 0 ) ? 1 : -1 ; | |
yinc = ( dy > 0 ) ? 1 : -1 ; | |
dx = ( dx > 0 ) ? dx : -dx ; | |
dy = ( dy > 0 ) ? dy : -dy ; | |
_DrawPixel( x, y ) ; | |
if ( dx > dy ) | |
{ | |
cumul = dx / 2 ; | |
for ( i = 1 ; i <= dx ; i++ ) | |
{ | |
x += xinc ; | |
cumul += dy ; | |
if ( cumul >= dx ) | |
{ | |
cumul -= dx ; | |
y += yinc ; | |
} | |
_DrawPixel( x, y ) ; | |
} | |
} | |
else | |
{ | |
cumul = dy / 2 ; | |
for ( i = 1 ; i <= dy ; i++ ) | |
{ | |
y += yinc ; | |
cumul += dx ; | |
if ( cumul >= dy ) | |
{ | |
cumul -= dy ; | |
x += xinc ; | |
} | |
_DrawPixel( x, y ) ; | |
} | |
} | |
return 0 ; | |
} | |
/*---------------------------------------------------------------------------- | |
* Exported functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief Fills the given LCD buffer with a particular color. | |
* | |
* \param color Fill color. | |
*/ | |
void LCDD_Fill( uint32_t dwColor ) | |
{ | |
sLCDDLayer *pDisp = LCDD_GetCanvas(); | |
_SetFrontColor(dwColor); | |
_HideCanvas(); | |
_FillRect( 0, 0, pDisp->wImgW, pDisp->wImgH ); | |
_ShowCanvas(); | |
} | |
void LCDD_Fill0(void) | |
{ | |
sLCDDLayer *pDisp = LCDD_GetCanvas(); | |
_HideCanvas(); | |
_SetFrontColor(0xFF0000); | |
_FillRect( 0, 0, pDisp->wImgW/3, pDisp->wImgH ); | |
_SetFrontColor(0x00FF00); | |
_FillRect( pDisp->wImgW/3, 0, pDisp->wImgW/3+pDisp->wImgW/3, pDisp->wImgH ); | |
_SetFrontColor(0x0000FF); | |
_FillRect( pDisp->wImgW/3+pDisp->wImgW/3, 0, pDisp->wImgW, pDisp->wImgH ); | |
_ShowCanvas(); | |
} | |
/** | |
* \brief Draw a pixel on LCD of given color. | |
* | |
* \param x X-coordinate of pixel. | |
* \param y Y-coordinate of pixel. | |
* \param color Pixel color. | |
*/ | |
extern void LCDD_DrawPixel( uint32_t x, uint32_t y, uint32_t color ) | |
{ | |
_SetFrontColor(color); | |
_HideCanvas(); | |
_DrawPixel(x, y); | |
_ShowCanvas(); | |
} | |
/** | |
* \brief Read a pixel from LCD. | |
* | |
* \param x X-coordinate of pixel. | |
* \param y Y-coordinate of pixel. | |
* | |
* \return color Readed pixel color. | |
*/ | |
extern uint32_t LCDD_ReadPixel( uint32_t x, uint32_t y ) | |
{ | |
sLCDDLayer *pDisp = LCDD_GetCanvas(); | |
uint8_t* buffer = pDisp->pBuffer; | |
uint16_t w = pDisp->wImgW; | |
//uint16_t h = pDisp->wImgH; | |
uint16_t cw = pDisp->bMode/8; /* color width */ | |
uint32_t rw = w * cw; /* row width in bytes */ | |
uint8_t *pPix; | |
uint32_t color = 0; | |
if (buffer == NULL) return 0; | |
if (rw & 0x3) rw = (rw | 0x3) + 1; /* 4-byte aligned rows */ | |
pPix = &buffer[x * rw + cw * y]; | |
switch (pDisp->bMode) | |
{ | |
case 16: /* TRGB 1555 */ | |
color = pPix[0] | (pPix[1] << 8); | |
break; | |
case 24: /* RGB 888 */ | |
color = pPix[0] | (pPix[1] << 8) | (pPix[2] << 16); | |
break; | |
case 32: /* ARGB 8888 */ | |
color = pPix[0] | (pPix[1] << 8) | (pPix[2] << 16) | (pPix[3] << 24); | |
break; | |
} | |
return color; | |
} | |
/** | |
* \brief Draw a line on LCD, horizontal and vertical line are supported. | |
* | |
* \param x1 X-coordinate of line start. | |
* \param y1 Y-coordinate of line start. | |
* \param x2 X-coordinate of line end. | |
* \param y2 Y-coordinate of line end. | |
* \param color Pixel color. | |
*/ | |
extern void LCDD_DrawLine( uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, uint32_t color ) | |
{ | |
_SetFrontColor(color); | |
if ( (x1 == x2) || (y1 == y2) ) | |
{ | |
LCDD_DrawFilledRectangle(x1, y1, x2, y2, color); | |
} | |
else | |
{ | |
_HideCanvas(); | |
_DrawLineBresenham(x1, y1, x2, y2); | |
_ShowCanvas(); | |
} | |
} | |
/** | |
* \brief Draws a rectangle on LCD, at the given coordinates. | |
* | |
* \param x X-coordinate of upper-left rectangle corner. | |
* \param y Y-coordinate of upper-left rectangle corner. | |
* \param width Rectangle width in pixels. | |
* \param height Rectangle height in pixels. | |
* \param color Rectangle color. | |
*/ | |
extern void LCDD_DrawRectangle( uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color ) | |
{ | |
uint32_t x1 = x + width - 1; | |
uint32_t y1 = y + height - 1; | |
_SetFrontColor(color); | |
_HideCanvas(); | |
_FillRect(x , y , x1, y ); | |
_FillRect(x1, y , x1, y1); | |
_FillRect(x , y , x , y1); | |
_FillRect(x , y1, x1, y1); | |
_ShowCanvas(); | |
} | |
/** | |
* \brief Draws a rectangle with fill inside on LCD, at the given coordinates. | |
* | |
* \param dwX1 X-coordinate of upper-left rectangle corner. | |
* \param dwY1 Y-coordinate of upper-left rectangle corner. | |
* \param dwX2 X-coordinate of down-right rectangle corner. | |
* \param dwY2 Y-coordinate of down-right rectangle corner. | |
* \param color Rectangle color. | |
*/ | |
extern void LCDD_DrawFilledRectangle( uint32_t dwX1, uint32_t dwY1, | |
uint32_t dwX2, uint32_t dwY2, | |
uint32_t dwColor ) | |
{ | |
_SetFrontColor(dwColor); | |
_HideCanvas(); | |
_FillRect(dwX1, dwY1, dwX2, dwY2); | |
_ShowCanvas(); | |
} | |
/** | |
* \brief Draws a circle on LCD, at the given coordinates. | |
* | |
* \param dwX X-coordinate of circle center. | |
* \param dwY Y-coordinate of circle center. | |
* \param dwR circle radius. | |
* \param dwColor circle color. | |
*/ | |
extern void LCDD_DrawCircle( uint32_t dwX, uint32_t dwY, uint32_t dwR, uint32_t dwColor ) | |
{ | |
int32_t d; /* Decision Variable */ | |
uint32_t curX; /* Current X Value */ | |
uint32_t curY; /* Current Y Value */ | |
if (dwR == 0) return; | |
_SetFrontColor(dwColor); | |
d = 3 - (dwR << 1); | |
curX = 0; | |
curY = dwR; | |
_HideCanvas(); | |
while (curX <= curY) | |
{ | |
_DrawPixel(dwX + curX, dwY + curY); | |
_DrawPixel(dwX + curX, dwY - curY); | |
_DrawPixel(dwX - curX, dwY + curY); | |
_DrawPixel(dwX - curX, dwY - curY); | |
_DrawPixel(dwX + curY, dwY + curX); | |
_DrawPixel(dwX + curY, dwY - curX); | |
_DrawPixel(dwX - curY, dwY + curX); | |
_DrawPixel(dwX - curY, dwY - curX); | |
if (d < 0) { | |
d += (curX << 2) + 6; | |
} | |
else { | |
d += ((curX - curY) << 2) + 10; | |
curY--; | |
} | |
curX++; | |
} | |
_ShowCanvas(); | |
} | |
/** | |
* \brief Draws a filled circle on LCD, at the given coordinates. | |
* | |
* \param dwX X-coordinate of circle center. | |
* \param dwY Y-coordinate of circle center. | |
* \param dwR circle radius. | |
* \param dwColor circle color. | |
*/ | |
void LCDD_DrawFilledCircle( uint32_t dwX, uint32_t dwY, uint32_t dwR, uint32_t dwColor ) | |
{ | |
signed int d ; // Decision Variable | |
uint32_t dwCurX ; // Current X Value | |
uint32_t dwCurY ; // Current Y Value | |
uint32_t dwXmin, dwYmin; | |
if (dwR == 0) return; | |
_SetFrontColor(dwColor); | |
d = 3 - (dwR << 1) ; | |
dwCurX = 0 ; | |
dwCurY = dwR ; | |
_HideCanvas(); | |
while ( dwCurX <= dwCurY ) | |
{ | |
dwXmin = (dwCurX > dwX) ? 0 : dwX-dwCurX; | |
dwYmin = (dwCurY > dwY) ? 0 : dwY-dwCurY; | |
_FillRect( dwXmin, dwYmin, dwX+dwCurX, dwYmin ) ; | |
_FillRect( dwXmin, dwY+dwCurY, dwX+dwCurX, dwY+dwCurY ) ; | |
dwXmin = (dwCurY > dwX) ? 0 : dwX-dwCurY; | |
dwYmin = (dwCurX > dwY) ? 0 : dwY-dwCurX; | |
_FillRect( dwXmin, dwYmin, dwX+dwCurY, dwYmin ) ; | |
_FillRect( dwXmin, dwY+dwCurX, dwX+dwCurY, dwY+dwCurX ) ; | |
if ( d < 0 ) | |
{ | |
d += (dwCurX << 2) + 6 ; | |
} | |
else | |
{ | |
d += ((dwCurX - dwCurY) << 2) + 10; | |
dwCurY-- ; | |
} | |
dwCurX++ ; | |
} | |
_ShowCanvas(); | |
} | |
/** | |
* \brief Draws a string inside a LCD buffer, at the given coordinates. Line breaks | |
* will be honored. | |
* | |
* \param x X-coordinate of string top-left corner. | |
* \param y Y-coordinate of string top-left corner. | |
* \param pString String to display. | |
* \param color String color. | |
*/ | |
extern void LCDD_DrawString( uint32_t x, uint32_t y, const char *pString, uint32_t color ) | |
{ | |
uint32_t xorg = x; | |
while (*pString) | |
{ | |
if (*pString == '\n') | |
{ | |
y += gFont.height + 2; x = xorg; | |
} | |
else | |
{ | |
LCDD_DrawChar(x, y, *pString, color); | |
x += gFont.width + 2; | |
} | |
pString ++; | |
} | |
} | |
/** | |
* \brief Draws a string inside a LCD buffer, at the given coordinates | |
* with given background color. Line breaks will be honored. | |
* | |
* \param x X-coordinate of string top-left corner. | |
* \param y Y-coordinate of string top-left corner. | |
* \param pString String to display. | |
* \param fontColor String color. | |
* \param bgColor Background color. | |
*/ | |
extern void LCDD_DrawStringWithBGColor( uint32_t x, uint32_t y, const char *pString, uint32_t fontColor, uint32_t bgColor ) | |
{ | |
uint32_t xorg = x; | |
while (*pString) | |
{ | |
if (*pString == '\n') | |
{ | |
y += gFont.height + 2; x = xorg; | |
} | |
else | |
{ | |
LCDD_DrawCharWithBGColor(x, y, *pString, fontColor, bgColor); | |
x += gFont.width + 2; | |
} | |
pString ++; | |
} | |
} | |
/** | |
* \brief Returns the width & height in pixels that a string will occupy on the screen | |
* if drawn using LCDD_DrawString. | |
* | |
* \param pString String. | |
* \param pWidth Pointer for storing the string width (optional). | |
* \param pHeight Pointer for storing the string height (optional). | |
* | |
* \return String width in pixels. | |
*/ | |
extern void LCDD_GetStringSize( const char *pString, uint32_t *pWidth, uint32_t *pHeight ) | |
{ | |
uint32_t width = 0; | |
uint32_t height = gFont.height; | |
while (*pString) | |
{ | |
if (*pString == '\n') height += gFont.height + 2; | |
else width += gFont.height + 2; | |
pString ++; | |
} | |
if (width > 0) width -= 2; | |
if (pWidth) *pWidth = width; | |
if (pHeight)*pHeight = height; | |
} | |
/** | |
* \brief Draw a raw image at given position on LCD. | |
* | |
* \param x X-coordinate of image start. | |
* \param y Y-coordinate of image start. | |
* \param pImage Image buffer. | |
* \param width Image width. | |
* \param height Image height. | |
*/ | |
void LCDD_DrawImage( uint32_t dwX, uint32_t dwY, const uint8_t *pImage, uint32_t dwWidth, uint32_t dwHeight ) | |
{ | |
sLCDDLayer *pDisp = LCDD_GetCanvas(); | |
uint16_t cw = pDisp->bMode/8; /* color width */ | |
uint32_t rw = pDisp->wImgW * cw; /* Row width in bytes */ | |
uint32_t rws = dwWidth * cw; /* Source Row Width */ | |
uint32_t rl = (rw & 0x3) ? ((rw | 0x3) + 1) : rw; /* Aligned length*/ | |
uint32_t rls = (rws & 0x3) ? ((rws | 0x3) + 1) : rws; /* Aligned length */ | |
uint8_t *pSrc, *pDst; | |
uint32_t i; | |
pSrc = (uint8_t*)pImage; | |
pDst = pDisp->pBuffer; | |
pDst = &pDst[dwX*cw + dwY*rl]; | |
for (i = 0; i < dwHeight; i ++) | |
{ | |
memcpy(pDst, pSrc, rws); | |
pSrc = &pSrc[rls]; | |
pDst = &pDst[rl]; | |
} | |
} | |
/** | |
* \brief Clear a window with an color. | |
* | |
* \param dwX X-coordinate of the window. | |
* \param dwY Y-coordinate of the window. | |
* \param dwWidth window width. | |
* \param dwHeight window height. | |
* \param dwColor background color | |
*/ | |
extern void LCDD_ClearWindow( uint32_t dwX, uint32_t dwY, uint32_t dwWidth, uint32_t dwHeight, uint32_t dwColor ) | |
{ | |
_SetFrontColor(dwColor); | |
_HideCanvas(); | |
_FillRect(0, 0, dwX + dwWidth - 1, dwY + dwHeight - 1); | |
_ShowCanvas(); | |
} | |