acidportal

- 😈 Worlds smallest Evil Portal on a LilyGo T-QT
git clone git://git.acid.vegas/acidportal.git
Log | Files | Refs | Archive | README | LICENSE

Rotated_Sprite_2.ino (7619B)

      1 // This example plots a rotated Sprite into another Sprite and then the resultant composited
      2 // Sprite is pushed to the TFT screen. This example is for a 240 x 320 screen.
      3 
      4 // The motivation for developing this capability is that animated dials can be drawn easily
      5 // and the complex calculations involved are handled by the TFT_eSPI library. To create a dial
      6 // with a moving needle a graphic of a meter needle is plotted at a specified angle into another
      7 // Sprite that contains the dial face. When the needle Sprite is pushed to the dial Sprite the
      8 // plotting ensures two pivot points for each Sprite coincide with pixel level accuracy.
      9 
     10 // Two rotation pivot points must be set, one for the first Sprite and one for the second
     11 // Sprite using setPivot(). These pivot points do not need to be within the Sprite boundaries.
     12 
     13 // In this example a needle graphic is also be plotted direct to a defined TFT pivot point.
     14 
     15 // The rotation angle is in degrees, an angle of 0 means no Sprite rotation.
     16 
     17 // The pushRotated() function works with 1, 8 and 16 bit per pixel (bpp) Sprites.
     18 
     19 // For 1 bpp Sprites the foreground and background colours are defined with the
     20 // member function setBitmapColor(foregroundColor, backgroundColor).
     21 
     22 // Created by Bodmer 6/1/19 as an example to the TFT_eSPI library:
     23 // https://github.com/Bodmer/TFT_eSPI
     24 
     25 #include <TFT_eSPI.h>
     26 
     27 TFT_eSPI tft = TFT_eSPI();
     28 
     29 TFT_eSprite dial   = TFT_eSprite(&tft); // Sprite object for dial
     30 TFT_eSprite needle = TFT_eSprite(&tft); // Sprite object for needle
     31 
     32 uint32_t startMillis;
     33 
     34 int16_t angle = 0;
     35 
     36 // =======================================================================================
     37 // Setup
     38 // =======================================================================================
     39 
     40 void setup()   {
     41   Serial.begin(250000); // Debug only
     42 
     43   tft.begin();
     44   tft.setRotation(1);
     45 
     46   // Clear TFT screen
     47   tft.fillScreen(TFT_NAVY);
     48 
     49   // Create the dial Sprite and dial (this temporarily hijacks the use of the needle Sprite)
     50   createDialScale(-120, 120, 30);   // create scale (start angle, end angle, increment angle)
     51   drawEmptyDial("Label", 12345);    // draw the centre of dial in the Sprite
     52 
     53   dial.pushSprite(110, 0);          // push a copy of the dial to the screen so we can see it
     54 
     55   // Create the needle Sprite
     56   createNeedle();                // draw the needle graphic
     57   needle.pushSprite(95, 7);    // push a copy of the needle to the screen so we can see it
     58 }
     59 
     60 // =======================================================================================
     61 // Loop
     62 // =======================================================================================
     63 
     64 void loop() {
     65 
     66   // Push the needle sprite to the dial Sprite at different angles and then push the dial to the screen
     67   // Use angle increments in range 1 to 6 for smoother or faster movement
     68   for (int16_t angle = -120; angle <= 120; angle += 2) {
     69     plotDial(0, 0, angle, "RPM", angle + 120);
     70     delay(25);
     71     yield(); // Avoid a watchdog time-out
     72   }
     73 
     74   delay(1000);  // Pause
     75 
     76   // Update the dial Sprite with decreasing angle and plot to screen at 0,0, no delay
     77   for (int16_t angle = 120; angle >= -120; angle -= 2) {
     78     plotDial(0, 0, angle, "RPM", angle + 120);
     79     yield(); // Avoid a watchdog time-out
     80   }
     81 
     82   // Now show plotting of the rotated needle direct to the TFT
     83   tft.setPivot(45, 150); // Set the TFT pivot point that the needle will rotate around
     84 
     85   // The needle graphic has a black border so if the angle increment is small
     86   // (6 degrees or less in this case) it wipes the last needle position when
     87   // it is rotated and hence it clears the swept area to black
     88   for (int16_t angle = 0; angle <= 360; angle += 5)
     89   {
     90     needle.pushRotated(angle); // Plot direct to TFT at specified angle
     91     yield();                   // Avoid a watchdog time-out
     92   }
     93 }
     94 
     95 // =======================================================================================
     96 // Create the dial sprite, the dial outer and place scale markers
     97 // =======================================================================================
     98 
     99 void createDialScale(int16_t start_angle, int16_t end_angle, int16_t increment)
    100 {
    101   // Create the dial Sprite
    102   dial.setColorDepth(8);       // Size is odd (i.e. 91) so there is a centre pixel at 45,45
    103   dial.createSprite(91, 91);   // 8bpp requires 91 * 91 = 8281 bytes
    104   dial.setPivot(45, 45);       // set pivot in middle of dial Sprite
    105 
    106   // Draw dial outline
    107   dial.fillSprite(TFT_TRANSPARENT);           // Fill with transparent colour
    108   dial.fillCircle(45, 45, 43, TFT_DARKGREY);  // Draw dial outer
    109 
    110   // Hijack the use of the needle Sprite since that has not been used yet!
    111   needle.createSprite(3, 3);     // 3 pixels wide, 3 high
    112   needle.fillSprite(TFT_WHITE);  // Fill with white
    113   needle.setPivot(1, 43);        //  Set pivot point x to the Sprite centre and y to marker radius
    114 
    115   for (int16_t angle = start_angle; angle <= end_angle; angle += increment) {
    116     needle.pushRotated(&dial, angle); // Sprite is used to make scale markers
    117     yield(); // Avoid a watchdog time-out
    118   }
    119 
    120   needle.deleteSprite(); // Delete the hijacked Sprite
    121 }
    122 
    123 
    124 // =======================================================================================
    125 // Add the empty dial face with label and value
    126 // =======================================================================================
    127 
    128 void drawEmptyDial(String label, int16_t val)
    129 {
    130   // Draw black face
    131   dial.fillCircle(45, 45, 40, TFT_BLACK);
    132   dial.drawPixel(45, 45, TFT_WHITE);        // For demo only, mark pivot point with a while pixel
    133 
    134   dial.setTextDatum(TC_DATUM);              // Draw dial text
    135   dial.drawString(label, 45, 15, 2);
    136   dial.drawNumber(val, 45, 60, 2);
    137 }
    138 
    139 // =======================================================================================
    140 // Update the dial and plot to screen with needle at defined angle
    141 // =======================================================================================
    142 
    143 void plotDial(int16_t x, int16_t y, int16_t angle, String label, uint16_t val)
    144 {
    145   // Draw the blank dial in the Sprite, add label and number
    146   drawEmptyDial(label, val);
    147 
    148   // Push a rotated needle Sprite to the dial Sprite, with black as transparent colour
    149   needle.pushRotated(&dial, angle, TFT_BLACK); // dial is the destination Sprite
    150 
    151   // Push the resultant dial Sprite to the screen, with transparent colour
    152   dial.pushSprite(x, y, TFT_TRANSPARENT);
    153 }
    154 
    155 // =======================================================================================
    156 // Create the needle Sprite and the image of the needle
    157 // =======================================================================================
    158 
    159 void createNeedle(void)
    160 {
    161   needle.setColorDepth(8);
    162   needle.createSprite(11, 49); // create the needle Sprite 11 pixels wide by 49 high
    163 
    164   needle.fillSprite(TFT_BLACK);          // Fill with black
    165 
    166   // Define needle pivot point
    167   uint16_t piv_x = needle.width() / 2;   // x pivot of Sprite (middle)
    168   uint16_t piv_y = needle.height() - 10; // y pivot of Sprite (10 pixels from bottom)
    169   needle.setPivot(piv_x, piv_y);         // Set pivot point in this Sprite
    170 
    171   // Draw the red needle with a yellow tip
    172   // Keep needle tip 1 pixel inside dial circle to avoid leaving stray pixels
    173   needle.fillRect(piv_x - 1, 2, 3, piv_y + 8, TFT_RED);
    174   needle.fillRect(piv_x - 1, 2, 3, 5, TFT_YELLOW);
    175 
    176   // Draw needle centre boss
    177   needle.fillCircle(piv_x, piv_y, 5, TFT_MAROON);
    178   needle.drawPixel( piv_x, piv_y, TFT_WHITE);     // Mark needle pivot point with a white pixel
    179 }
    180 
    181 // =======================================================================================