--- /dev/null
+/* ----------------------------------------------------------------------------\r
+ * SAM Software Package License\r
+ * ----------------------------------------------------------------------------\r
+ * Copyright (c) 2015, Atmel Corporation\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the disclaimer below.\r
+ *\r
+ * Atmel's name may not be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * ----------------------------------------------------------------------------\r
+ */\r
+\r
+/** \addtogroup lcdd_draw\r
+ *\r
+ * Implementation of draw function on LCD, Include draw text, image\r
+ * and basic shapes (line, rectangle, circle).\r
+ *\r
+ */\r
+\r
+/** \file */\r
+\r
+/*----------------------------------------------------------------------------\r
+ * Headers\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "board.h"\r
+\r
+#include "video/lcdd.h"\r
+\r
+#include "lcd_draw.h"\r
+#include "lcd_font.h"\r
+#include "font.h"\r
+\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <assert.h>\r
+\r
+/*----------------------------------------------------------------------------\r
+ * Local variable\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/** Front color cache */\r
+static uint32_t front_color;\r
+\r
+/*----------------------------------------------------------------------------\r
+ * Local functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Hide canvas layer\r
+ */\r
+static void _hide_canvas(void)\r
+{\r
+ //lcdd_enable_layer(lcdd_get_canvas()->layer_id, false);\r
+}\r
+\r
+/**\r
+ * Update canvas\r
+ */\r
+static void _show_canvas(void)\r
+{\r
+ //lcdd_enable_layer(lcdd_get_canvas()->layer_id, true);\r
+}\r
+\r
+/**\r
+ * Set front color\r
+ * \param color Pixel color.\r
+ */\r
+static void _set_front_color(uint32_t color)\r
+{\r
+ front_color = color;\r
+}\r
+\r
+/**\r
+ * \brief Draw a pixel on LCD of front color.\r
+ *\r
+ * \param dwX X-coordinate of pixel.\r
+ * \param dwY Y-coordinate of pixel.\r
+ */\r
+static void _draw_pixel(uint32_t dwX, uint32_t dwY)\r
+{\r
+ struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+ uint8_t *buffer = pDisp->buffer;\r
+ uint16_t w = pDisp->width;\r
+ //uint16_t h = pDisp->height;\r
+ uint16_t cw = pDisp->bpp / 8; /* color width */\r
+ uint32_t rw = w * cw; /* row width in bytes */\r
+ //uint8_t r, g, b;\r
+ uint8_t *pPix;\r
+\r
+ if (buffer == NULL)\r
+ return;\r
+\r
+ if (rw & 0x3)\r
+ rw = (rw | 0x3) + 1; /* 4-byte aligned rows */\r
+ pPix = &buffer[dwY * rw + cw * dwX];\r
+\r
+ switch (pDisp->bpp) {\r
+ case 16: /* TRGB 1555 */\r
+ pPix[0] = (front_color) & 0xFF;\r
+ pPix[1] = (front_color >> 8) & 0xFF;\r
+ break;\r
+ case 24: /* RGB 888 */\r
+ pPix[0] = (front_color) & 0xFF;\r
+ pPix[1] = (front_color >> 8) & 0xFF;\r
+ pPix[2] = (front_color >> 16) & 0xFF;\r
+ break;\r
+ case 32: /* ARGB 8888 */\r
+ pPix[0] = (front_color) & 0xFF;\r
+ pPix[1] = (front_color >> 8) & 0xFF;\r
+ pPix[2] = (front_color >> 16) & 0xFF;\r
+ pPix[3] = (front_color >> 24) & 0xFF;\r
+ break;\r
+ }\r
+}\r
+\r
+/**\r
+ * \brief Fill rectangle with front color.\r
+ * \param dwX1 X-coordinate of top left.\r
+ * \param dwY1 Y-coordinate of top left.\r
+ * \param dwX2 X-coordinate of bottom right.\r
+ * \param dwY1 Y-coordinate of bottom right.\r
+ */\r
+static void _fill_rect(uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2)\r
+{\r
+ struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+ uint16_t w = pDisp->width;\r
+ uint16_t cw = pDisp->bpp / 8; /* color width */\r
+ uint32_t rw = w * cw; /* row width in bytes */\r
+ uint8_t *base = pDisp->buffer;\r
+ uint8_t *buffer = pDisp->buffer;\r
+ uint32_t fillStart, fillEnd;\r
+ uint32_t i;\r
+ if (buffer == NULL)\r
+ return;\r
+\r
+ /* 4-byte aligned rows */\r
+ if (rw & 0x3)\r
+ rw = (rw | 0x3) + 1;\r
+ /* Buffer address for the starting row */\r
+ base = &buffer[dwY1 * rw];\r
+\r
+ fillStart = dwX1 * cw;\r
+ fillEnd = dwX2 * cw;\r
+\r
+#if 1 /* Memcopy pixel */\r
+ buffer = base;\r
+ for (; dwY1 <= dwY2; dwY1++) {\r
+ for (i = fillStart; i <= fillEnd; i += cw) {\r
+ memcpy(&buffer[i], &front_color, cw);\r
+ }\r
+ buffer = &buffer[rw];\r
+ }\r
+#endif\r
+\r
+#if 0 /* Pixel by pixel */\r
+ for (; dwY1 <= dwY2; dwY1++) {\r
+ for (i = dwX1; i <= dwX2; i++) {\r
+ _draw_pixel(i, dwY1);\r
+ }\r
+ }\r
+#endif\r
+\r
+#if 0 /* Optimized */\r
+ /* First row */\r
+ for (i = fillStart; i <= fillEnd; i += cw) {\r
+ memcpy(&base[i], &front_color, cw);\r
+ }\r
+ /* Next rows, copy first */\r
+ buffer = &base[rw + fillStart];\r
+ for (i = dwY1 + 1; i <= dwY2; i++) {\r
+ memcpy(buffer, &base[fillStart], fillEnd - fillStart + cw);\r
+ buffer = &buffer[rw];\r
+ }\r
+#endif\r
+}\r
+\r
+/**\r
+ * \brief Draw a line on LCD, which is not horizontal or vertical.\r
+ *\r
+ * \param dwX1 X-coordinate of line start.\r
+ * \param dwY1 Y-coordinate of line start.\r
+ * \param dwX2 X-coordinate of line end.\r
+ * \param dwY2 Y-coordinate of line end.\r
+ */\r
+\r
+/*\r
+static uint32_t _draw_line_bresenham (uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2)\r
+{\r
+ int dx, dy;\r
+ int i;\r
+ int xinc, yinc, cumul;\r
+ int x, y;\r
+\r
+ x = dwX1;\r
+ y = dwY1;\r
+ dx = dwX2 - dwX1;\r
+ dy = dwY2 - dwY1;\r
+\r
+ xinc = (dx > 0) ? 1 : -1;\r
+ yinc = (dy > 0) ? 1 : -1;\r
+ dx = (dx > 0) ? dx : -dx;\r
+ dy = (dy > 0) ? dy : -dy;\r
+\r
+ _draw_pixel(x, y);\r
+\r
+ if (dx > dy) {\r
+ cumul = dx / 2;\r
+ for (i = 1; i <= dx; i++) {\r
+ x += xinc;\r
+ cumul += dy;\r
+\r
+ if (cumul >= dx) {\r
+ cumul -= dx;\r
+ y += yinc;\r
+ }\r
+ _draw_pixel(x, y);\r
+ }\r
+ } else {\r
+ cumul = dy / 2;\r
+ for (i = 1; i <= dy; i++) {\r
+ y += yinc;\r
+ cumul += dx;\r
+\r
+ if (cumul >= dy) {\r
+ cumul -= dy;\r
+ x += xinc;\r
+ }\r
+\r
+ _draw_pixel(x, y);\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+*/\r
+\r
+static uint32_t _draw_line_bresenham (uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2)\r
+{\r
+ int dx = abs(dwX2 - dwX1);\r
+ int dy = abs(dwY2 - dwY1);\r
+ int sx = (dwX1 < dwX2) ? 1 : -1;\r
+ int sy = (dwY1 < dwY2) ? 1 : -1;\r
+ int err = dx - dy;\r
+ int e2 ;\r
+\r
+ while (1) {\r
+ _draw_pixel(dwX1, dwY1);\r
+ if ((dwX1 == dwX2) && (dwY1 == dwY2))\r
+ break;\r
+ e2 = 2 * err;\r
+ if (e2 > -dy) {\r
+ err -= dy; dwX1 += sx;\r
+ }\r
+ if (e2 < dx) {\r
+ err += dx; dwY1 += sy;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+/*----------------------------------------------------------------------------\r
+ * Exported functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * \brief Fills the given LCD buffer with a particular color.\r
+ *\r
+ * \param color Fill color.\r
+ */\r
+void lcdd_fill(uint32_t color)\r
+{\r
+ struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ _fill_rect(0, 0, pDisp->width, pDisp->height);\r
+ _show_canvas();\r
+}\r
+\r
+void lcdd_fill_white(void)\r
+{\r
+ struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+ _hide_canvas();\r
+ _set_front_color(0x0000FF);\r
+ _fill_rect(0, 0, pDisp->width / 3, pDisp->height);\r
+ _set_front_color(0xFFFFFF);\r
+ _fill_rect(pDisp->width/3, 0, pDisp->width/3+pDisp->width/3, pDisp->height);\r
+ _set_front_color(0xFF0000);\r
+ _fill_rect(pDisp->width/3+pDisp->width/3, 0, pDisp->width-1, pDisp->height);\r
+ _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draw a pixel on LCD of given color.\r
+ *\r
+ * \param x X-coordinate of pixel.\r
+ * \param y Y-coordinate of pixel.\r
+ * \param color Pixel color.\r
+ */\r
+void lcdd_draw_pixel(uint32_t x, uint32_t y, uint32_t color)\r
+{\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ _draw_pixel(x, y);\r
+ _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Read a pixel from LCD.\r
+ *\r
+ * \param x X-coordinate of pixel.\r
+ * \param y Y-coordinate of pixel.\r
+ *\r
+ * \return color Readed pixel color.\r
+ */\r
+extern uint32_t lcdd_read_pixel(uint32_t x, uint32_t y)\r
+{\r
+ struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+ uint8_t *buffer = pDisp->buffer;\r
+ uint16_t w = pDisp->width;\r
+ //uint16_t h = pDisp->height;\r
+ uint16_t cw = pDisp->bpp / 8; /* color width */\r
+ uint32_t rw = w * cw; /* row width in bytes */\r
+ uint8_t *pPix;\r
+ uint32_t color = 0;\r
+\r
+ if (buffer == NULL)\r
+ return 0;\r
+\r
+ if (rw & 0x3)\r
+ rw = (rw | 0x3) + 1; /* 4-byte aligned rows */\r
+ pPix = &buffer[x * rw + cw * y];\r
+\r
+ switch (pDisp->bpp) {\r
+ case 16: /* TRGB 1555 */\r
+ color = pPix[0] | (pPix[1] << 8);\r
+ break;\r
+ case 24: /* RGB 888 */\r
+ color = pPix[0] | (pPix[1] << 8) | (pPix[2] << 16);\r
+ break;\r
+ case 32: /* ARGB 8888 */\r
+ color =\r
+ pPix[0] | (pPix[1] << 8) | (pPix[2] << 16) | (pPix[3] <<\r
+ 24);\r
+ break;\r
+ }\r
+ return color;\r
+}\r
+\r
+/**\r
+ * \brief Draw a line on LCD, horizontal and vertical line are supported.\r
+ *\r
+ * \param x1 X-coordinate of line start.\r
+ * \param y1 Y-coordinate of line start.\r
+ * \param x2 X-coordinate of line end.\r
+ * \param y2 Y-coordinate of line end.\r
+ * \param color Pixel color.\r
+ */\r
+void lcdd_draw_line(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2,\r
+ uint32_t color)\r
+{\r
+ _set_front_color(color);\r
+\r
+ if ((x1 == x2) && (y1 > y2)) {\r
+ SWAP(y1, y2);\r
+ }\r
+ if ((x1 > x2) & (y1 == y2)) {\r
+ SWAP(x1, x2);\r
+ }\r
+\r
+ if ((x1 == x2) || (y1 == y2)) {\r
+ lcdd_draw_filled_rectangle(x1, y1, x2, y2, color);\r
+ } else {\r
+ _hide_canvas();\r
+ _draw_line_bresenham(x1, y1, x2, y2);\r
+ _show_canvas();\r
+ }\r
+}\r
+\r
+/**\r
+ * \brief Draws a rectangle on LCD, at the given coordinates.\r
+ *\r
+ * \param x X-coordinate of upper-left rectangle corner.\r
+ * \param y Y-coordinate of upper-left rectangle corner.\r
+ * \param width Rectangle width in pixels.\r
+ * \param height Rectangle height in pixels.\r
+ * \param color Rectangle color.\r
+ */\r
+void lcdd_draw_rectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height,\r
+ uint32_t color)\r
+{\r
+ uint32_t x1 = x + width - 1;\r
+ uint32_t y1 = y + height - 1;\r
+\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ _fill_rect(x, y, x1, y);\r
+ _fill_rect(x1, y, x1, y1);\r
+ _fill_rect(x, y, x, y1);\r
+ _fill_rect(x, y1, x1, y1);\r
+ _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a rectangle with fill inside on LCD, at the given coordinates.\r
+ *\r
+ * \param dwX1 X-coordinate of upper-left rectangle corner.\r
+ * \param dwY1 Y-coordinate of upper-left rectangle corner.\r
+ * \param dwX2 X-coordinate of down-right rectangle corner.\r
+ * \param dwY2 Y-coordinate of down-right rectangle corner.\r
+ * \param color Rectangle color.\r
+ */\r
+void lcdd_draw_filled_rectangle(uint32_t dwX1, uint32_t dwY1,\r
+ uint32_t dwX2, uint32_t dwY2, uint32_t color)\r
+{\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ _fill_rect(dwX1, dwY1, dwX2, dwY2);\r
+ _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a circle on LCD, at the given coordinates.\r
+ *\r
+ * \param dwX X-coordinate of circle center.\r
+ * \param dwY Y-coordinate of circle center.\r
+ * \param dwR circle radius.\r
+ * \param color circle color.\r
+ */\r
+void lcdd_draw_circle(uint32_t dwX, uint32_t dwY, uint32_t dwR, uint32_t color)\r
+{\r
+ int32_t d; /* Decision Variable */\r
+ uint32_t curX; /* Current X Value */\r
+ uint32_t curY; /* Current Y Value */\r
+\r
+ if (dwR == 0)\r
+ return;\r
+ _set_front_color(color);\r
+\r
+ d = 3 - (dwR << 1);\r
+ curX = 0;\r
+ curY = dwR;\r
+\r
+ _hide_canvas();\r
+ while (curX <= curY) {\r
+ _draw_pixel(dwX + curX, dwY + curY);\r
+ _draw_pixel(dwX + curX, dwY - curY);\r
+ _draw_pixel(dwX - curX, dwY + curY);\r
+ _draw_pixel(dwX - curX, dwY - curY);\r
+ _draw_pixel(dwX + curY, dwY + curX);\r
+ _draw_pixel(dwX + curY, dwY - curX);\r
+ _draw_pixel(dwX - curY, dwY + curX);\r
+ _draw_pixel(dwX - curY, dwY - curX);\r
+\r
+ if (d < 0) {\r
+ d += (curX << 2) + 6;\r
+ } else {\r
+ d += ((curX - curY) << 2) + 10;\r
+ curY--;\r
+ }\r
+ curX++;\r
+ }\r
+ _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a filled circle on LCD, at the given coordinates.\r
+ *\r
+ * \param dwX X-coordinate of circle center.\r
+ * \param dwY Y-coordinate of circle center.\r
+ * \param dwR circle radius.\r
+ * \param color circle color.\r
+ */\r
+void lcdd_draw_filled_circle(uint32_t dwX, uint32_t dwY, uint32_t dwR,\r
+ uint32_t color)\r
+{\r
+ signed int d; // Decision Variable\r
+ uint32_t dwCurX; // Current X Value\r
+ uint32_t dwCurY; // Current Y Value\r
+ uint32_t dwXmin, dwYmin;\r
+\r
+ if (dwR == 0)\r
+ return;\r
+ _set_front_color(color);\r
+\r
+ d = 3 - (dwR << 1);\r
+ dwCurX = 0;\r
+ dwCurY = dwR;\r
+\r
+ _hide_canvas();\r
+ while (dwCurX <= dwCurY) {\r
+ dwXmin = (dwCurX > dwX) ? 0 : dwX - dwCurX;\r
+ dwYmin = (dwCurY > dwY) ? 0 : dwY - dwCurY;\r
+ _fill_rect(dwXmin, dwYmin, dwX + dwCurX, dwYmin);\r
+ _fill_rect(dwXmin, dwY + dwCurY, dwX + dwCurX, dwY + dwCurY);\r
+ dwXmin = (dwCurY > dwX) ? 0 : dwX - dwCurY;\r
+ dwYmin = (dwCurX > dwY) ? 0 : dwY - dwCurX;\r
+ _fill_rect(dwXmin, dwYmin, dwX + dwCurY, dwYmin);\r
+ _fill_rect(dwXmin, dwY + dwCurX, dwX + dwCurY, dwY + dwCurX);\r
+\r
+ if (d < 0) {\r
+ d += (dwCurX << 2) + 6;\r
+ } else {\r
+ d += ((dwCurX - dwCurY) << 2) + 10;\r
+ dwCurY--;\r
+ }\r
+\r
+ dwCurX++;\r
+ }\r
+ _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a string inside a LCD buffer, at the given coordinates. Line breaks\r
+ * will be honored.\r
+ *\r
+ * \param x X-coordinate of string top-left corner.\r
+ * \param y Y-coordinate of string top-left corner.\r
+ * \param p_string String to display.\r
+ * \param color String color.\r
+ */\r
+void lcdd_draw_string(uint32_t x, uint32_t y, const char *p_string, uint32_t color)\r
+{\r
+ uint32_t xorg = x;\r
+ uint8_t font_sel = lcdd_get_selected_font();\r
+ uint8_t width = font_param[font_sel].width ;\r
+ uint8_t height = font_param[font_sel].height;\r
+ uint8_t char_space = font_param[font_sel].char_space;\r
+\r
+ /* Font 10*8 reverse height and width */\r
+ if (font_sel == FONT10x8) {\r
+ width = font_param[font_sel].height ;\r
+ height = font_param[font_sel].width;\r
+ }\r
+\r
+ while (*p_string) {\r
+ if (*p_string == '\n') {\r
+ y += height + char_space;\r
+ x = xorg;\r
+ } else {\r
+ lcdd_draw_char(x, y, *p_string, color);\r
+ x += width + char_space;\r
+ }\r
+ p_string++;\r
+ }\r
+}\r
+\r
+/**\r
+ * \brief Draws a string inside a LCD buffer, at the given coordinates\r
+ * with given background color. Line breaks will be honored.\r
+ *\r
+ * \param x X-coordinate of string top-left corner.\r
+ * \param y Y-coordinate of string top-left corner.\r
+ * \param p_string String to display.\r
+ * \param fontColor String color.\r
+ * \param bgColor Background color.\r
+ */\r
+void lcdd_draw_string_with_bgcolor(uint32_t x, uint32_t y,\r
+ const char *p_string,\r
+ uint32_t fontColor,\r
+ uint32_t bgColor)\r
+{\r
+ uint32_t xorg = x;\r
+ uint8_t font_sel = lcdd_get_selected_font();\r
+ uint8_t width = font_param[font_sel].width ;\r
+ uint8_t height = font_param[font_sel].height;\r
+ uint8_t char_space = font_param[font_sel].char_space;\r
+\r
+ /* Font 10*8 reverse height and width */\r
+ if (font_sel == FONT10x8) {\r
+ width = font_param[font_sel].height ;\r
+ height = font_param[font_sel].width;\r
+ }\r
+\r
+ while (*p_string) {\r
+ if (*p_string == '\n') {\r
+ y += height + char_space;;\r
+ x = xorg;\r
+ } else {\r
+ lcdd_draw_char_with_bgcolor(x, y, *p_string, fontColor, bgColor);\r
+ x += width + char_space;;\r
+ }\r
+ p_string++;\r
+ }\r
+}\r
+\r
+/**\r
+ * \brief Returns the width & height in pixels that a string will occupy on the screen\r
+ * if drawn using lcdd_draw_string.\r
+ *\r
+ * \param p_string String.\r
+ * \param p_width Pointer for storing the string width (optional).\r
+ * \param p_height Pointer for storing the string height (optional).\r
+ *\r
+ * \return String width in pixels.\r
+ */\r
+void lcdd_get_string_size(const char *p_string, uint32_t * p_width, uint32_t * p_height)\r
+{\r
+ uint8_t font_sel = lcdd_get_selected_font();\r
+ uint8_t width = font_param[font_sel].width;\r
+ uint8_t height = font_param[font_sel].height;\r
+ uint8_t char_space = font_param[font_sel].char_space;\r
+ uint32_t str_width = 0;\r
+\r
+ /* Font 10*8 reverse height and width */\r
+ if (font_sel == FONT10x8) {\r
+ width = font_param[font_sel].height ;\r
+ height = font_param[font_sel].width;\r
+ }\r
+\r
+ while (*p_string) {\r
+ if (*p_string == '\n')\r
+ height += height + char_space;\r
+ else\r
+ str_width += width + char_space;\r
+ p_string++;\r
+ }\r
+ if (width > 0)\r
+ str_width -= char_space;\r
+\r
+ if (p_width != NULL)\r
+ *p_width = str_width;\r
+ if (p_height != NULL)\r
+ *p_height = height;\r
+}\r
+\r
+/**\r
+ * \brief Draw a raw image at given position on LCD.\r
+ *\r
+ * \param dwX X-coordinate of image start.\r
+ * \param dwY Y-coordinate of image start.\r
+ * \param pImage Image buffer.\r
+ * \param width Image width.\r
+ * \param height Image height.\r
+ */\r
+void lcdd_draw_image(uint32_t dwX, uint32_t dwY, const uint8_t * pImage,\r
+ uint32_t width, uint32_t height)\r
+{\r
+ struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+ uint16_t cw = pDisp->bpp / 8; /* color width */\r
+ uint32_t rw = pDisp->width * cw; /* Row width in bytes */\r
+ uint32_t rws = width * cw; /* Source Row Width */\r
+ uint32_t rl = (rw & 0x3) ? ((rw | 0x3) + 1) : rw; /* Aligned length */\r
+ uint32_t rls = (rws & 0x3) ? ((rws | 0x3) + 1) : rws; /* Aligned length */\r
+ uint8_t *pSrc, *pDst;\r
+ uint32_t i;\r
+\r
+ pSrc = (uint8_t *) pImage;\r
+ pDst = pDisp->buffer;\r
+ pDst = &pDst[dwX * cw + dwY * rl];\r
+\r
+ for (i = 0; i < height; i++) {\r
+ memcpy(pDst, pSrc, rws);\r
+ pSrc = &pSrc[rls];\r
+ pDst = &pDst[rl];\r
+ }\r
+}\r
+\r
+/**\r
+ * \brief Clear a window with an color.\r
+ *\r
+ * \param dwX X-coordinate of the window.\r
+ * \param dwY Y-coordinate of the window.\r
+ * \param width window width.\r
+ * \param height window height.\r
+ * \param color background color\r
+ */\r
+void lcdd_clear_window(uint32_t dwX, uint32_t dwY, uint32_t width,\r
+ uint32_t height, uint32_t color)\r
+{\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ _fill_rect(0, 0, dwX + width - 1, dwY + height - 1);\r
+ _show_canvas();\r
+}\r
+\r
+/*----------------------------------------------------------------------------\r
+ * Local functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Draw fast vertical line\r
+ */\r
+void lcdd_draw_fast_vline (uint32_t x, uint32_t y, uint32_t h, uint32_t color)\r
+{\r
+ lcdd_draw_line(x, y, x, y+h-1, color);\r
+}\r
+/**\r
+ * Draw fast horizontal line\r
+ */\r
+void lcdd_draw_fast_hline (uint32_t x, uint32_t y, uint32_t w, uint32_t color)\r
+{\r
+ lcdd_draw_line(x, y, x+w-1, y, color);\r
+}\r
+/**\r
+ * Fill rectangle with color\r
+ */\r
+static void _lcdd_fill_rectangle (uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)\r
+{\r
+ uint32_t i;\r
+ for (i=x; i<x+w; i++) lcdd_draw_fast_vline(i, y, h, color);\r
+}\r
+/**\r
+ * Draw a circle\r
+ */\r
+static void _lcdd_draw_circle (uint32_t x0, uint32_t y0, uint32_t r, uint8_t corner, uint32_t color)\r
+{\r
+ int32_t f = 1 - r;\r
+ int32_t ddF_x = 1;\r
+ int32_t ddF_y = -2 * (int32_t)r;\r
+ int32_t x = 0;\r
+ int32_t y = r;\r
+\r
+ while (x<y) {\r
+ if (f >= 0)\r
+ {\r
+ y--;\r
+ ddF_y += 2;\r
+ f += ddF_y;\r
+ }\r
+ x++;\r
+ ddF_x += 2;\r
+ f += ddF_x;\r
+ if (corner & 0x4) {\r
+ _draw_pixel(x0 + x, y0 + y);\r
+ _draw_pixel(x0 + y, y0 + x);\r
+ }\r
+ if (corner & 0x2) {\r
+ _draw_pixel(x0 + x, y0 - y);\r
+ _draw_pixel(x0 + y, y0 - x);\r
+ }\r
+ if (corner & 0x8) {\r
+ _draw_pixel(x0 - y, y0 + x);\r
+ _draw_pixel(x0 - x, y0 + y);\r
+ }\r
+ if (corner & 0x1) {\r
+ _draw_pixel(x0 - y, y0 - x);\r
+ _draw_pixel(x0 - x, y0 - y);\r
+ }\r
+ }\r
+}\r
+/**\r
+ * Fill a circle\r
+ */\r
+static void _lcdd_fill_circle (uint32_t x0, uint32_t y0, uint32_t r, uint8_t corner, uint32_t delta, uint32_t color)\r
+{\r
+ int32_t f = 1 - r;\r
+ int32_t ddF_x = 1;\r
+ int32_t ddF_y = -2 * (int32_t)r;\r
+ int32_t x = 0;\r
+ int32_t y = r;\r
+\r
+ while (x<y) {\r
+ if (f >= 0) {\r
+ y--;\r
+ ddF_y += 2;\r
+ f += ddF_y;\r
+ }\r
+ x++;\r
+ ddF_x += 2;\r
+ f += ddF_x;\r
+\r
+ if (corner & 0x1) {\r
+ lcdd_draw_fast_vline(x0+x, y0-y, 2*y+1+delta, color);\r
+ lcdd_draw_fast_vline(x0+y, y0-x, 2*x+1+delta, color);\r
+ }\r
+ if (corner & 0x2) {\r
+ lcdd_draw_fast_vline(x0-x, y0-y, 2*y+1+delta, color);\r
+ lcdd_draw_fast_vline(x0-y, y0-x, 2*x+1+delta, color);\r
+ }\r
+ }\r
+}\r
+\r
+/*----------------------------------------------------------------------------\r
+ * Global functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Draw a rectangle with rounded corners\r
+ */\r
+void lcdd_draw_rounded_rect (uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t r, uint32_t color)\r
+{\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ // smarter version\r
+ lcdd_draw_fast_hline(x+r, y, w-2*r, color); // Top\r
+ lcdd_draw_fast_hline(x+r, y+h-1, w-2*r, color); // Bottom\r
+ lcdd_draw_fast_vline(x, y+r, h-2*r, color); // Left\r
+ lcdd_draw_fast_vline(x+w-1, y+r, h-2*r, color); // Right\r
+ // draw four corners\r
+ _lcdd_draw_circle(x+r, y+r, r, 1, color);\r
+ _lcdd_draw_circle(x+w-r-1, y+r, r, 2, color);\r
+ _lcdd_draw_circle(x+w-r-1, y+h-r-1, r, 4, color);\r
+ _lcdd_draw_circle(x+r, y+h-r-1, r, 8, color);\r
+ _show_canvas();\r
+}\r
+/**\r
+ * Fill a rectangle with rounded corners\r
+ */\r
+void lcdd_fill_rounded_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t r, uint32_t color)\r
+{\r
+ _set_front_color(color);\r
+ _hide_canvas();\r
+ if (w>(2*r)) {\r
+ _lcdd_fill_rectangle(x+r, y, w-(2*r), h, color);\r
+ // draw four corners\r
+ _lcdd_fill_circle(x+w-r-1, y+r, r, 1, h-2*r-1, color);\r
+ _lcdd_fill_circle(x+r, y+r, r, 2, h-2*r-1, color);\r
+ }\r
+ _show_canvas();\r
+}\r