acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.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 // =======================================================================================