blob: 266277c9f9c96e4f2a3db056a2c606cdae5177cf [file] [log] [blame]
/* ----------------------------------------------------------------------------
* 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();
}