| /* ---------------------------------------------------------------------------- | |
| * 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(); | |
| } | |