Redid font rendering code
[hackover2013-badge-firmware.git] / drivers / lcd / tft / drawing.c
index 61acdf5..f7b2ab5 100644 (file)
 /*                                                                        */
 /**************************************************************************/
 
+/**************************************************************************/
+/*!
+    @brief  Swaps values a and b
+*/
+/**************************************************************************/
+void drawSwap(uint32_t a, uint32_t b)
+{
+  uint32_t t;
+  t = a;
+  a = b;
+  b = t;
+}
+
 /**************************************************************************/
 /*!
     @brief  Draws a single bitmap character
 */
 /**************************************************************************/
-void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const uint8_t *glyph, uint8_t glyphHeightPages, uint8_t glyphWidthBits)
+void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const uint8_t *glyph, uint8_t cols, uint8_t rows)
 {
   uint16_t verticalPage, horizBit, currentY, currentX;
   uint16_t indexIntoGlyph;
 
+  uint16_t _row, _col, _colPages;
+
   // set initial current y
   currentY = yPixel;
   currentX = xPixel;
 
-  // for each page of the glyph
-  for (verticalPage = glyphHeightPages; verticalPage > 0; --verticalPage)
+  // Figure out how many columns worth of data we have
+  if (cols % 8)
+    _colPages = cols / 8 + 1;
+  else
+    _colPages = cols / 8;
+
+  for (_row = 0; _row < rows; _row++)
   {
-    // for each horizontol bit
-    for (horizBit = 0; horizBit < glyphWidthBits; ++horizBit)
+    for (_col = 0; _col < _colPages; _col++)
     {
-      // next byte
-      indexIntoGlyph = (glyphHeightPages * horizBit) + verticalPage - 1;
-      
-      currentX = xPixel + (horizBit);
+      if (_row == 0)
+        indexIntoGlyph = _col;
+      else
+        indexIntoGlyph = (_row * _colPages) + _col;
+
+      currentY = yPixel + _row;
+      currentX = xPixel + (_col*8);
       // send the data byte
       if (glyph[indexIntoGlyph] & (0X80)) drawPixel(currentX, currentY, color);
-      if (glyph[indexIntoGlyph] & (0X40)) drawPixel(currentX, currentY - 1, color);
-      if (glyph[indexIntoGlyph] & (0X20)) drawPixel(currentX, currentY - 2, color);
-      if (glyph[indexIntoGlyph] & (0X10)) drawPixel(currentX, currentY - 3, color);
-      if (glyph[indexIntoGlyph] & (0X08)) drawPixel(currentX, currentY - 4, color);
-      if (glyph[indexIntoGlyph] & (0X04)) drawPixel(currentX, currentY - 5, color);
-      if (glyph[indexIntoGlyph] & (0X02)) drawPixel(currentX, currentY - 6, color);
-      if (glyph[indexIntoGlyph] & (0X01)) drawPixel(currentX, currentY - 7, color);
+      if (glyph[indexIntoGlyph] & (0X40)) drawPixel(currentX+1, currentY, color);
+      if (glyph[indexIntoGlyph] & (0X20)) drawPixel(currentX+2, currentY, color);
+      if (glyph[indexIntoGlyph] & (0X10)) drawPixel(currentX+3, currentY, color);
+      if (glyph[indexIntoGlyph] & (0X08)) drawPixel(currentX+4, currentY, color);
+      if (glyph[indexIntoGlyph] & (0X04)) drawPixel(currentX+5, currentY, color);
+      if (glyph[indexIntoGlyph] & (0X02)) drawPixel(currentX+6, currentY, color);
+      if (glyph[indexIntoGlyph] & (0X01)) drawPixel(currentX+7, currentY, color);
     }
-    // next line of pages
-    currentY += 8;
   }
 }
 
@@ -330,7 +350,9 @@ void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInf
     }        
     
     // Send individual characters
-    drawCharBitmap(currentX, y, color, &fontInfo->data[charOffset], fontInfo->heightPages, charWidth);
+    // We need to manually calculate width in pages since this is screwy with variable width fonts
+    //uint8_t heightPages = charWidth % 8 ? charWidth / 8 : charWidth / 8 + 1;
+    drawCharBitmap(currentX, y, color, &fontInfo->data[charOffset], charWidth, fontInfo->height);
 
     // next char X
     currentX += charWidth + 1;
@@ -450,9 +472,6 @@ void drawLineDotted ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16
   // Check if we can use the optimised vertical line method.
   // This can make a huge difference in performance, but may
   // not work properly on every LCD controller:
-  // ex.: drawCircleFilled(120, 160, 50, COLOR_RED);
-  //      = 678834 cycles using lcdDrawVLine w/ILI9328   =  9.43mS @ 72MHz
-  //      = 7546261 w/o lcdDrawVLine, setting each pixel = 104.8mS @ 72MHz
   if ((x0 == x1) && (empty == 0))
   {
     // Warning: This may actually be slower than drawing individual pixels on 
@@ -649,6 +668,86 @@ void drawCircleFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, uint
   }
 }
 
+/**************************************************************************/
+/*!
+    @brief  Draws a filled rounded corner
+
+    @param[in]  xCenter
+                The horizontal center of the circle
+    @param[in]  yCenter
+                The vertical center of the circle
+    @param[in]  radius
+                The circle's radius in pixels
+    @param[in]  position
+                The position of the corner, which affects how it will
+                be rendered
+    @param[in]  color
+                Color used when drawing
+*/
+/**************************************************************************/
+void drawCornerFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, drawCornerPosition_t position, uint16_t color)
+{
+  int16_t f = 1 - radius;
+  int16_t ddF_x = 1;
+  int16_t ddF_y = -2 * radius;
+  int16_t x = 0;
+  int16_t y = radius;
+  int16_t xc_px, yc_my, xc_mx, xc_py, yc_mx, xc_my;
+  int16_t lcdWidth = lcdGetWidth();
+
+  switch (position)
+  {
+    case DRAW_CORNERPOSITION_TOPRIGHT:
+    case DRAW_CORNERPOSITION_TOPLEFT:
+      if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter-radius, xCenter, yCenter, color);
+      break;
+    case DRAW_CORNERPOSITION_BOTTOMRIGHT:
+    case DRAW_CORNERPOSITION_BOTTOMLEFT:
+      if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter, xCenter, (yCenter-radius) + (2*radius), color);
+      break;
+  }
+  
+  while (x<y) 
+  {
+    if (f >= 0) 
+    {
+      y--;
+      ddF_y += 2;
+      f += ddF_y;
+    }
+    x++;
+    ddF_x += 2;
+    f += ddF_x;
+
+    xc_px = xCenter+x;
+    xc_mx = xCenter-x;
+    xc_py = xCenter+y;
+    xc_my = xCenter-y;
+    yc_mx = yCenter-x;
+    yc_my = yCenter-y;
+
+    switch (position)
+    {
+      case DRAW_CORNERPOSITION_TOPRIGHT:
+        if ((xc_px < lcdWidth) && (xc_px >= 0)) drawLine(xc_px, yc_my, xc_px, yCenter, color);
+        if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yc_mx, xc_py, yCenter, color);
+        break;
+      case DRAW_CORNERPOSITION_BOTTOMRIGHT:
+        if ((xc_px < lcdWidth) && (xc_px >= 0)) drawLine(xc_px, yCenter, xc_px, yc_my + 2*y, color);
+        if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yCenter, xc_py, yc_mx + 2*x, color);
+        break;
+      case DRAW_CORNERPOSITION_TOPLEFT:
+        if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yc_my, xc_mx, yCenter, color);
+        if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yc_mx, xc_my, yCenter, color);
+        break;
+      case DRAW_CORNERPOSITION_BOTTOMLEFT:
+        if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yCenter, xc_mx, yc_my + 2*y, color);
+        if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yCenter, xc_my, yc_mx + 2*x, color);
+        break;
+    }
+  }
+}
+
 /**************************************************************************/
 /*!
     @brief  Draws a simple arrow of the specified width
@@ -890,6 +989,122 @@ void drawRectangleRounded ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
   }
 }
 
+/**************************************************************************/
+/*!
+    @brief  Draws a triangle
+
+    @param[in]  x0
+                x co-ordinate for point 0
+    @param[in]  y0
+                y co-ordinate for point 0
+    @param[in]  x1
+                x co-ordinate for point 1
+    @param[in]  y1
+                y co-ordinate for point 1
+    @param[in]  x2
+                x co-ordinate for point 2
+    @param[in]  y2
+                y co-ordinate for point 2
+    @param[in]  color
+                Color used when drawing
+*/
+/**************************************************************************/
+void drawTriangle ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
+{
+  drawLine(x0, y0, x1, y1, color);
+  drawLine(x1, y1, x2, y2, color);
+  drawLine(x2, y2, x0, y0, color);  
+}
+
+/**************************************************************************/
+/*!
+    @brief  Draws a filled triangle
+
+    @param[in]  x0
+                x co-ordinate for point 0
+    @param[in]  y0
+                y co-ordinate for point 0
+    @param[in]  x1
+                x co-ordinate for point 1
+    @param[in]  y1
+                y co-ordinate for point 1
+    @param[in]  x2
+                x co-ordinate for point 2
+    @param[in]  y2
+                y co-ordinate for point 2
+    @param[in]  color
+                Fill color
+
+    @section Example
+
+    @code
+
+    // Draw a white triangle
+    drawTriangleFilled ( 100, 10, 20, 120, 230, 290, COLOR_WHITE);
+    // Draw black circles at each point of the triangle
+    drawCircleFilled(100, 10, 2, COLOR_BLACK);
+    drawCircleFilled(20, 120, 2, COLOR_BLACK);
+    drawCircleFilled(230, 290, 2, COLOR_BLACK);
+
+    @endcode
+*/
+/**************************************************************************/
+void drawTriangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
+{
+  // Re-order vertices by ascending Y values (smallest first)
+  if (y0 > y1) {
+    drawSwap(y0, y1); drawSwap(x0, x1);
+  }
+  if (y1 > y2) {
+    drawSwap(y2, y1); drawSwap(x2, x1);
+  }
+  if (y0 > y1) {
+    drawSwap(y0, y1); drawSwap(x0, x1);
+  }
+
+  int32_t dx1, dx2, dx3;    // Interpolation deltas
+  int32_t sx1, sx2, sy;     // Scanline co-ordinates
+
+  sx1=sx2=x0 * 1000;        // Use fixed point math for x axis values
+  sy=y0;
+
+  // Calculate interpolation deltas
+  if (y1-y0 > 0) dx1=((x1-x0)*1000)/(y1-y0);
+    else dx1=0;
+  if (y2-y0 > 0) dx2=((x2-x0)*1000)/(y2-y0);
+    else dx2=0;
+  if (y2-y1 > 0) dx3=((x2-x1)*1000)/(y2-y1);
+    else dx3=0;
+
+  // Render scanlines (horizontal lines are the fastest rendering method)
+  if (dx1 > dx2) 
+  {
+    for(; sy<=y1; sy++, sx1+=dx2, sx2+=dx1)
+    {
+      drawLine(sx1/1000, sy, sx2/1000, sy, color);
+    }
+    sx2 = x1*1000;
+    sy = y1;
+    for(; sy<=y2; sy++, sx1+=dx2, sx2+=dx3)
+    {
+      drawLine(sx1/1000, sy, sx2/1000, sy, color);
+    }
+  } 
+  else 
+  {
+    for(; sy<=y1; sy++, sx1+=dx1, sx2+=dx2)
+    {
+      drawLine(sx1/1000, sy, sx2/1000, sy, color);
+    }
+    sx1 = x1*1000;
+    sy = y1;
+    for(; sy<=y2; sy++, sx1+=dx3, sx2+=dx2)
+    {
+      drawLine(sx1/1000, sy, sx2/1000, sy, color);
+    }
+  }
+}
+
 /**************************************************************************/
 /*!
     @brief  Converts a 24-bit RGB color to an equivalent 16-bit RGB565 value
@@ -1062,27 +1277,17 @@ void drawProgressBar ( uint16_t x, uint16_t y, uint16_t width, uint16_t height,
     @code 
 
     #include "drivers/lcd/tft/drawing.h"  
-    #include "drivers/lcd/tft/fonts/dejavusansbold9.h"
+    #include "drivers/lcd/tft/fonts/dejavusans9.h"
 
     // Draw two buttons using Vera Sans Bold 9
-    drawButton(20, 195, 200, 35, &dejaVuSansBold9ptFontInfo, 7, COLOR_DARKERGRAY, COLOR_DARKERGRAY, COLOR_WHITE, "System Settings");
-    drawButton(20, 235, 200, 35, &dejaVuSansBold9ptFontInfo, 7, COLOR_LIMEGREENDIM, COLOR_LIMEGREEN, COLOR_BLACK, "System Settings");
+    drawButton(20, 195, 200, 35, &dejaVuSans9ptFontInfo, 7, COLOR_GRAY_80, COLOR_GRAY_80, COLOR_WHITE, "System Settings");
+    drawButton(20, 235, 200, 35, &dejaVuSans9ptFontInfo, 7, COLOR_THEME_LIMEGREEN_DARKER, COLOR_THEME_LIMEGREEN_BASE, COLOR_BLACK, "System Settings");
 
     @endcode
 */
 /**************************************************************************/
 void drawButton(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const FONT_INFO *fontInfo, uint16_t fontHeight, uint16_t borderclr, uint16_t fillclr, uint16_t fontclr, char* text)
 {
-  uint16_t border, fill, font, activeborder, activefill, activefont;
-
-  // Set colors
-  border            = COLOR_GRAY_30;
-  fill              = COLOR_GRAY_30;
-  font              = COLOR_WHITE;
-  activeborder      = COLOR_THEME_DEFAULT_DARKER;
-  activefill        = COLOR_THEME_DEFAULT_BASE;
-  activefont        = COLOR_BLACK;
-
   // Border
   drawRectangleRounded(x, y, x + width, y + height, borderclr, 5, DRAW_ROUNDEDCORNERS_ALL);
   // Fill
This page took 0.029004 seconds and 4 git commands to generate.