├── LICENSE ├── examples └── TFTShape │ └── TFTShape.ino ├── images ├── screenshot_20260.png ├── screenshot_20266.png ├── screenshot_20287.png ├── screenshot_20293.png ├── screenshot_20320.png ├── screenshot_35807.png ├── screenshot_35845.png ├── screenshot_35853.png ├── screenshot_35854.png ├── screenshot_4554.png ├── screenshot_4559.png ├── screenshot_4564.png ├── screenshot_4571.png ├── screenshot_4572.png ├── screenshot_4598.png ├── screenshot_51345.png ├── screenshot_51372.png ├── screenshot_51387.png ├── screenshot_66902.png └── screenshot_66925.png ├── library.properties ├── readme.md └── src ├── TFTLineShape.cpp ├── TFTLineShape.h ├── TFTLinestripShape.cpp ├── TFTLinestripShape.h ├── TFTShape.cpp ├── TFTShape.h ├── TFTShapeBuilder.cpp ├── TFTShapeBuilder.h ├── TFTSimplexNoise.cpp ├── TFTSimplexNoise.h └── TFTSplineShape.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 javalang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/TFTShape/TFTShape.ino: -------------------------------------------------------------------------------- 1 | //uncomment for use with ODROID 2 | //#define USE_ODROID 3 | 4 | #ifdef USE_ODROID 5 | #include "ego.h" 6 | #else 7 | #include 8 | TFT_eSPI tft = TFT_eSPI(); 9 | #endif 10 | #include 11 | 12 | //uncomment this for offscreen display 13 | #define OFFSCREEN 14 | 15 | #ifdef OFFSCREEN 16 | TFT_eSprite tft2 = TFT_eSprite(&tft); 17 | #else 18 | #define tft2 tft 19 | #endif 20 | #define TFT_GREY 0xa514 21 | long start,startRender; 22 | 23 | void header(String title) { 24 | tft2.fillScreen(TFT_NAVY); 25 | tft2.drawFastVLine(120,0,360,TFT_DARKGREY); 26 | tft2.drawFastHLine(0,160,240,TFT_DARKGREY); 27 | TC_String(tft2,title,5,4,TFT_GREEN); 28 | start=millis(); 29 | startRender=start; 30 | } 31 | void footer(int dely=2000) { 32 | BC_String(tft2,"render/total time : "+String(millis()-startRender)+"/"+String(millis()-start)+" ms",5,2,TFT_WHITE); 33 | #ifdef OFFSCREEN 34 | tft2.pushSprite(0,0); 35 | #endif 36 | delay(dely); 37 | } 38 | 39 | void setup() { 40 | #ifdef USE_ODROID 41 | ego.begin(); 42 | #else 43 | tft.init(); 44 | #endif 45 | tft.setRotation(0); 46 | tft.fillScreen(TFT_BLUE); 47 | #ifdef OFFSCREEN 48 | //tft2.setColorDepth(8); //!!COLOR_DEPTH!!(default 16) 49 | tft2.createSprite(240,320); //Display dimension 50 | #endif 51 | TFTSimplexNoise::init(); 52 | //runTests(); 53 | 54 | while(true) { 55 | runTests(); 56 | pacman(); 57 | } 58 | 59 | } 60 | 61 | 62 | void loop() {} 63 | 64 | TFTShape pac1=TFTShapeBuilder::buildWedge(18,20,180+60,240); 65 | TFTShape pac2=TFTShapeBuilder::buildWedge(18,20,180+30,300); 66 | //**************************************** 67 | void pacman() { 68 | header("pacman"); 69 | int i=(millis()&0x200)?0:1; 70 | TFTShape & s =i?pac1:pac2; 71 | for(int i=0;i<4;i++) 72 | s.fillDraw(&tft2,120,80+i*60,TFT_BLACK,TFT_YELLOW); 73 | footer(); 74 | } 75 | 76 | TFTSplineShape theSpline(27,3,false);//43,3); 77 | //**************************************** 78 | void sineSpline() { 79 | header("sineSpline"); 80 | VEC2 buf[27]; 81 | for(int i=0;i<27;i++) { 82 | buf[i].x=(i-1)*10; 83 | buf[i].y=sin(i*15*M_PI/180+millis()/800.)*80; 84 | } 85 | theSpline.updateData(buf); 86 | startRender=millis(); 87 | theSpline.draw(&tft2,0,160,TFT_WHITE); 88 | footer(); 89 | } 90 | TFTSplineShape aSimplexSpline(27,5,false); 91 | //**************************************** 92 | void simplexSpline() { 93 | header("SimplexSpline"); 94 | VEC2 buf[27]; 95 | for(int i=0;i<27;i++) { 96 | buf[i].x=(i-1)*10; 97 | buf[i].y=TFTSimplexNoise::noise((i/8.)+millis()/800.,0)*80; 98 | } 99 | startRender=millis(); 100 | aSimplexSpline.updateData(buf); 101 | aSimplexSpline.draw(&tft2,0,160,TFT_WHITE); 102 | footer(); 103 | } 104 | TFTSplineShape randomLoopSpline(15,8,true); 105 | //**************************************** 106 | void randomSplineLoop() { 107 | header("randomSplineLoop"); 108 | VEC2 buf[15]; 109 | for(int i=0;i<15;i++) { 110 | buf[i].x=100-random(200); 111 | buf[i].y=100-random(200); 112 | } 113 | randomLoopSpline.updateData(buf); 114 | randomLoopSpline.draw(&tft2,120,160,TFT_WHITE); 115 | footer(); 116 | } 117 | //**************************************** 118 | void randomPoints() { 119 | header("randomPoints"); 120 | TFTShape shape=TFTShapeBuilder::buildRandomPoints(240); 121 | startRender=millis(); 122 | for(int i=0;i<240;i++) { 123 | //tft2.drawFastVLine(i,160+shape.getPoints()[i].y/4,5,TFT_WHITE); 124 | tft2.fillRect(i,160+shape.getPoints()[i].y,4,4,TFT_WHITE); 125 | } 126 | footer(); 127 | } 128 | //**************************************** 129 | void ngonSpline() { 130 | header("NgonSpline"); 131 | VEC2 buf[3]; 132 | TFTShapeBuilder::fillNgonVertices(buf,3,VEC2(80)); 133 | TFTSplineShape ngonspline(buf,3,12,true); 134 | startRender=millis(); 135 | ngonspline.fillDraw(&tft2,120,160,TFT_WHITE,TFT_DARKGREEN,2); 136 | footer(); 137 | } 138 | 139 | //**************************************** 140 | void tetris() { 141 | header("tetris"); 142 | TFTShape block=TFTShape({{0,-1},{0,0},{1,0},{2,0}}); block.setScale(20); 143 | TFTShape r= TFTShapeBuilder::buildRect(20); 144 | block.fillDraw(&tft2,120,160,r,TFT_WHITE,TFT_DARKGREEN); 145 | block.rotateBy(90); 146 | block.fillDraw(&tft2,120,40,r,TFT_WHITE,TFT_RED); 147 | block.rotateBy(90); 148 | block.fillDraw(&tft2,120,240,r,TFT_BLACK,TFT_YELLOW); 149 | footer(); 150 | } 151 | 152 | //**************************************** 153 | void pivotScale() { 154 | header("pivot scale"); 155 | TFTShape r=TFTShapeBuilder::buildRect(80); 156 | 157 | r.setPivot(0,-40); 158 | for(int i=0;i<10;i++) { 159 | r.scaleBy(.8)->draw(&tft2,120,100,TFT_WHITE); 160 | } 161 | r.reset(); r.draw(&tft2,120,100,TFT_GREEN); 162 | tft2.drawFastHLine(120-100,60,200,TFT_YELLOW); 163 | tft2.drawFastVLine(120,60-100,200,TFT_YELLOW); 164 | 165 | r.setPivot(0,0); 166 | for(int i=0;i<10;i++) { 167 | r.scaleBy(.8)->draw(&tft2,120,240,TFT_WHITE); 168 | } 169 | r.reset(); r.draw(&tft2,120,240,TFT_GREEN); 170 | tft2.drawFastHLine(120-100,240,200,TFT_YELLOW); 171 | tft2.drawFastVLine(120,240-100,200,TFT_YELLOW); 172 | 173 | 174 | footer(); 175 | } 176 | 177 | //**************************************** 178 | void pivotRot() { 179 | header("pivot rotation"); 180 | TFTShape r=TFTShapeBuilder::buildRect(80); 181 | 182 | r.setPivot(0,-40);r.setRotation(-30); 183 | for(int i=0;i<10;i++) { 184 | r.rotateBy(6)->draw(&tft2,120,100,TFT_WHITE); 185 | } 186 | r.reset(); r.draw(&tft2,120,100,TFT_GREEN); 187 | tft2.drawFastHLine(120-100,60,200,TFT_YELLOW); 188 | tft2.drawFastVLine(120,60-100,200,TFT_YELLOW); 189 | 190 | r.setPivot(0,0);r.setRotation(-30); 191 | for(int i=0;i<10;i++) { 192 | r.rotateBy(6)->draw(&tft2,120,240,TFT_WHITE); 193 | } 194 | r.reset(); r.draw(&tft2,120,240,TFT_GREEN); 195 | tft2.drawFastHLine(120-100,240,200,TFT_YELLOW); 196 | tft2.drawFastVLine(120,240-100,200,TFT_YELLOW); 197 | 198 | footer(); 199 | } 200 | //**************************************** 201 | void clock1() { 202 | header("analog-clock"); 203 | TFTShape dot=TFTShapeBuilder::buildNgon(3,12); dot.setScale(.5,1); 204 | TFTShape face=TFTShapeBuilder::buildNgon(12,100); 205 | //clock-face 206 | face.draw(&tft2,120,160,dot,TFT_WHITE); 207 | //hour-hand 208 | TFTShape hand=TFTShapeBuilder::buildNgon(5,60); 209 | hand.setScale(.08,.8); hand.setOffset(0,-30); hand.setRotation(170); 210 | hand.fill(&tft2,120,160,TFT_GREY); 211 | //minutes-hand 212 | hand.setScale(.08,1); hand.setRotation(240); 213 | hand.fill(&tft2,120,160,TFT_LIGHTGREY); 214 | //seconds-hand 215 | hand.setScale(.03,1); hand.setRotation(30); 216 | hand.fill(&tft2,120,160,TFT_RED); 217 | dot.fill(&tft2,120,160,TFT_RED); 218 | dot.setScale(.4); 219 | dot.fill(&tft2,120,160,TFT_DARKGREY); 220 | footer(); 221 | 222 | 223 | } 224 | //**************************************** 225 | void euro() { 226 | header("euro"); 227 | TFTShape s=TFTShapeBuilder::buildStar(5,12,5); 228 | s.setRotationFixed(true); 229 | TFTShape n=TFTShapeBuilder::buildNgon(12,80); 230 | startRender=millis(); 231 | n.fill(&tft2,120,160,s,TFT_YELLOW); 232 | footer(); 233 | } 234 | //**************************************** 235 | void fillstyles2() { 236 | header("fillstyles-2"); 237 | TFTShape r=TFTShapeBuilder::buildRect(8,16); 238 | TFTShape arc=TFTShapeBuilder::buildArc(24,80,210,300); 239 | startRender=millis(); 240 | arc.fill(&tft2,120,160,r,CR(120,0)); 241 | uint16_t c16; 242 | for(int i=0;i<320;i++) { 243 | tft2.drawFastHLine(210,i,20,CR::colorFromHSV(0,0,1.*i/320)); 244 | c16=((i/10)<<11)&0xffff; 245 | tft2.drawFastHLine(10,i,20,c16); 246 | } 247 | for(int i=0;i<240;i++) { 248 | tft2.drawFastVLine(i,40,20,CR::colorFromHSV(120,0.5,1.*i/240)); 249 | } 250 | 251 | footer(); 252 | } 253 | 254 | //**************************************** 255 | void fillstyles1() { 256 | header("fillstyles-1"); 257 | 258 | TFTShape r=TFTShapeBuilder::buildRect(40); 259 | startRender=millis(); 260 | r.fill(&tft2,120-80,160-60,TFT_GREEN); 261 | r.fill(&tft2,120-80,160,TFT_GREEN,2); 262 | r.fillH(&tft2,120-80,160+60,TFT_GREEN,2); 263 | r.fill(&tft2,120,160-60,TFT_GREEN,4); 264 | r.fillH(&tft2,120,160-60,TFT_GREEN,4); 265 | r.fill(&tft2,120,160,CR(0,120)); 266 | r.fillH(&tft2,120,160+60,CR(0,120)); 267 | 268 | 269 | r.fill(&tft2,120+80,160-60,TFT_WHITE,3); 270 | r.fillH(&tft2,120+80,160-60,TFT_WHITE,3); 271 | //r.draw(&tft2,120+80,160-60,TFT_WHITE); 272 | 273 | r.fill(&tft2,120+80,160,TFT_WHITE); 274 | r.fill(&tft2,120+80,160,TFT_BLACK,4); 275 | r.fillH(&tft2,120+80,160,TFT_BLACK,4); 276 | 277 | 278 | 279 | //r.fill(&tft2,120+80,160+60,TFT_WHITE); 280 | r.fill(&tft2,120+80,160+60,TFT_WHITE,7); 281 | r.fill(&tft2,120+80,160+60,TFT_WHITE,5); 282 | r.fillH(&tft2,120+80,160+60,TFT_WHITE,7); 283 | r.fillH(&tft2,120+80,160+60,TFT_WHITE,5); 284 | //for(int i=0;i<160;i++) { 285 | //tft2.drawFastHLine(120+80, 80+i,20,CR::colorFromHSV(100,0,i/160.)); 286 | //} 287 | 288 | footer(); 289 | } 290 | //**************************************** 291 | void lines2() { 292 | header("lines"); 293 | 294 | TFTLineShape lines=TFTLineShape({{-1,0},{1,0},{0,-1},{0,1}}); 295 | 296 | lines.setScale(50); 297 | lines.setRotation(30); 298 | startRender=millis(); 299 | lines.draw(&tft2,120,160-60,TFT_WHITE); 300 | lines.fill(&tft2,120,160+60,TFT_WHITE); 301 | footer(); 302 | } 303 | //**************************************** 304 | void grid_2() { 305 | header("grid-2"); 306 | TFTShape r=TFTShapeBuilder::buildRect(8); 307 | r.setRotationFixed(true); 308 | TFTShape grid=TFTShapeBuilder::buildGrid(9,9,160,160,true); 309 | startRender=millis(); 310 | grid.draw(&tft2,120,160,r,TFT_WHITE); 311 | 312 | footer(); 313 | } 314 | //**************************************** 315 | void grid_1() { 316 | header("grid-1"); 317 | TFTShape triangle=TFTShapeBuilder::buildRect(8); 318 | triangle.setRotationFixed(true); 319 | TFTShape grid=TFTShapeBuilder::buildGrid(9,9,160,160,false); 320 | startRender=millis(); 321 | grid.draw(&tft2,120,160,triangle,TFT_WHITE); 322 | //grid.dumpVerts(); 323 | 324 | footer(); 325 | } 326 | 327 | //**************************************** 328 | void star2() { 329 | header("star"); 330 | TFTShape star=TFTShapeBuilder::buildStar(12,80,40); 331 | startRender=millis(); 332 | star.fillDraw(&tft2,120,160,TFT_WHITE,TFT_DARKGREEN,2); 333 | 334 | footer(); 335 | } 336 | //**************************************** 337 | void linegrid() { 338 | header("linegrid"); 339 | TFTLineShape grid=TFTShapeBuilder::buildLineGrid(6,6,160,160); 340 | startRender=millis(); 341 | grid.draw(&tft2,120,160,TFT_WHITE); 342 | 343 | footer(); 344 | } 345 | //**************************************** 346 | void ngon() { 347 | header("Ngon"); 348 | TFTShape n1=TFTShapeBuilder::buildNgon(3,35); 349 | TFTShape n2=TFTShapeBuilder::buildNgon(4,35); 350 | TFTShape n3=TFTShapeBuilder::buildNgon(5,35); 351 | TFTShape n4=TFTShapeBuilder::buildNgon(6,35); 352 | TFTShape n5=TFTShapeBuilder::buildNgon(7,35); 353 | //TFTShape n6=TFTShapeBuilder::buildNgon(8,35); 354 | //TFTLinestripShape n6a(n6.getPoints(),n6.getNumPoints()); 355 | TFTLinestripShape n6b=TFTShapeBuilder::buildNgonLinestrip(8,VEC2(35)); 356 | n6b.addPoints({{0,0},{n6b.getPoints()[0].x,n6b.getPoints()[0].y}}); 357 | startRender=millis(); 358 | n1.fillDrawH(&tft2,120-60,160-80,TFT_WHITE,TFT_DARKGREEN,2); 359 | n2.fillDrawH(&tft2,120-60,160,TFT_WHITE,TFT_DARKGREEN,2); 360 | n3.fillDrawH(&tft2,120-60,160+80,TFT_WHITE,TFT_DARKGREEN,2); 361 | n4.fillDrawH(&tft2,120+60,160-80,TFT_WHITE,TFT_DARKGREEN,2); 362 | n5.fillDrawH(&tft2,120+60,160,TFT_WHITE,TFT_DARKGREEN,2); 363 | //n6.fillDrawH(&tft2,120+60,160+80,TFT_WHITE,TFT_DARKGREEN,2); 364 | n6b.fill(&tft2,120+60,160+80,TFT_WHITE); 365 | 366 | 367 | footer(); 368 | } 369 | //**************************************** 370 | void starSpline() { 371 | header("starSpline"); 372 | VEC2 buf[20]; 373 | TFTShapeBuilder::fillStarVertices(buf,10,VEC2(80),VEC2(40)); 374 | TFTSplineShape spline(buf,20,8,true); 375 | startRender=millis(); 376 | spline.fillH(&tft2,120,160,TFT_DARKGREEN,2); 377 | spline.draw(&tft2,120,160,TFT_WHITE); 378 | footer(); 379 | } 380 | //**************************************** 381 | void spline() { 382 | header("spline"); 383 | //TFTLinestripShape spline=TFTShapeBuilder::buildSpline( {{0,0},{1,0},{2,0},{3,-1},{4,0},{5,-5},{6,1},{7,0},{8,-1},{9,-1.5},{10,-1},{11,0},{12,0},{12,0}},3,false); 384 | TFTSplineShape spline( {{0,0},{1,0},{2,0},{3,-1},{4,0},{5,-5},{6,1},{7,0},{8,-1},{9,-1.5},{10,-1},{11,0},{12,0},{12,0}},3,false); 385 | spline.setScale(15); spline.setOffset(-6,0); 386 | startRender=millis(); 387 | spline.draw(&tft2,120,160-40,TFT_WHITE); 388 | spline.fillH(&tft2,120,160+80,TFT_WHITE); 389 | 390 | footer(); 391 | } 392 | //**************************************** 393 | void annularWedge() { 394 | header("annular wedge"); 395 | 396 | TFTShape w=TFTShapeBuilder::buildAnnularWedge(32,80,65,210,300); 397 | startRender=millis(); 398 | w.fillDrawH(&tft2,120,160,TFT_WHITE,TFT_DARKGREEN,2); 399 | 400 | footer(); 401 | } 402 | //**************************************** 403 | void arc2() { 404 | header("arc"); 405 | 406 | TFTShape a1=TFTShapeBuilder::buildArc(24,80,0,180); 407 | TFTShape a2=TFTShapeBuilder::buildArc(24,80,210,120); 408 | startRender=millis(); 409 | a1.fillDraw(&tft2,120,160,TFT_WHITE,TFT_DARKGREEN,2); 410 | a2.fillH(&tft2,120,160,TFT_RED,2); 411 | 412 | footer(); 413 | } 414 | //**************************************** 415 | void wedge2() { 416 | header("wedge"); 417 | 418 | TFTShape w1=TFTShapeBuilder::buildWedge(18,80,180,240); 419 | TFTShape w2=TFTShapeBuilder::buildWedge(18,80,60,120); 420 | startRender=millis(); 421 | w1.fillDraw(&tft2,120,160,TFT_WHITE,TFT_DARKGREEN,2); 422 | w2.fillDrawH(&tft2,130,170,TFT_WHITE,TFT_RED,2); 423 | 424 | footer(); 425 | } 426 | //**************************************** 427 | void rect() { 428 | header("rect"); 429 | 430 | TFTShape rect=TFTShapeBuilder::buildRect(200,250); 431 | startRender=millis(); 432 | rect.draw(&tft2,120,160,TFT_WHITE); 433 | for(int i=0;i<8;i++) { 434 | rect.scaleBy(.9)->draw(&tft2,120,160,TFT_WHITE); 435 | } 436 | rect.fillH(&tft2,120,160,TFT_DARKGREEN,2); 437 | 438 | footer(); 439 | } 440 | //**************************************** 441 | void gear() { 442 | header("gear"); 443 | 444 | TFTShape gear= TFTShapeBuilder::buildGear(20,65,55,6); 445 | startRender=millis(); 446 | gear.fillDraw(&tft2,120,160,TFT_WHITE,TFT_DARKGREEN,2); 447 | footer(); 448 | } 449 | 450 | //**************************************** 451 | void ellipse() { 452 | header("ellipse"); 453 | 454 | TFTShape ellipse=TFTShapeBuilder::buildEllipse(36,100,50); 455 | startRender=millis(); 456 | ellipse.fill(&tft2,120,160,TFT_DARKGREEN,2); 457 | for(int i=0;i<4;i++) { 458 | ellipse.rotateBy(45)->draw(&tft2,120,160,TFT_WHITE); 459 | } 460 | footer(); 461 | } 462 | //**************************************** 463 | void clock2() { 464 | header("analog-clock"); 465 | TFTShape dot=TFTShapeBuilder::buildNgon(3,8); 466 | TFTShape face=TFTShapeBuilder::buildNgon(12,100); 467 | //clock-face 468 | face.fill(&tft2,120,160,dot,TFT_GREY); 469 | int pivy=35; 470 | //hour-hand 471 | TFTShape hand=TFTShapeBuilder::buildNgon(5,60); 472 | hand.setScale(.08,.8); hand.setPivot(0,pivy); hand.setRotation(170); 473 | hand.fill(&tft2,120,160-pivy,TFT_GREY); 474 | //minutes-hand 475 | hand.setScale(.08,1); hand.setRotation(240); 476 | hand.fill(&tft2,120,160-pivy,TFT_LIGHTGREY); 477 | //seconds-hand 478 | hand.setScale(.03,1); hand.setRotation(30); 479 | hand.fill(&tft2,120,160-pivy,TFT_RED); 480 | dot.fill(&tft2,120,160,TFT_RED); 481 | dot.setScale(.4); 482 | dot.fill(&tft2,120,160,TFT_DARKGREY); 483 | footer(); 484 | } 485 | 486 | //**************************************** 487 | void runTests() { 488 | gear(); 489 | ellipse(); 490 | rect(); 491 | wedge2(); 492 | arc2(); 493 | annularWedge(); 494 | spline(); 495 | linegrid(); 496 | star2(); 497 | grid_1(); 498 | grid_2(); 499 | lines2(); 500 | fillstyles1(); 501 | fillstyles2(); 502 | euro(); 503 | clock1(); 504 | pivotRot(); 505 | pivotScale(); 506 | tetris(); 507 | ngon(); 508 | starSpline(); 509 | sineSpline(); 510 | simplexSpline(); 511 | randomSplineLoop(); 512 | randomPoints(); 513 | ngonSpline(); 514 | 515 | } 516 | -------------------------------------------------------------------------------- /images/screenshot_20260.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_20260.png -------------------------------------------------------------------------------- /images/screenshot_20266.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_20266.png -------------------------------------------------------------------------------- /images/screenshot_20287.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_20287.png -------------------------------------------------------------------------------- /images/screenshot_20293.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_20293.png -------------------------------------------------------------------------------- /images/screenshot_20320.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_20320.png -------------------------------------------------------------------------------- /images/screenshot_35807.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_35807.png -------------------------------------------------------------------------------- /images/screenshot_35845.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_35845.png -------------------------------------------------------------------------------- /images/screenshot_35853.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_35853.png -------------------------------------------------------------------------------- /images/screenshot_35854.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_35854.png -------------------------------------------------------------------------------- /images/screenshot_4554.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_4554.png -------------------------------------------------------------------------------- /images/screenshot_4559.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_4559.png -------------------------------------------------------------------------------- /images/screenshot_4564.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_4564.png -------------------------------------------------------------------------------- /images/screenshot_4571.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_4571.png -------------------------------------------------------------------------------- /images/screenshot_4572.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_4572.png -------------------------------------------------------------------------------- /images/screenshot_4598.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_4598.png -------------------------------------------------------------------------------- /images/screenshot_51345.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_51345.png -------------------------------------------------------------------------------- /images/screenshot_51372.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_51372.png -------------------------------------------------------------------------------- /images/screenshot_51387.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_51387.png -------------------------------------------------------------------------------- /images/screenshot_66902.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_66902.png -------------------------------------------------------------------------------- /images/screenshot_66925.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androdlang/TFTShape/940bc799d72fafc6f91b7768b62d899b0d095a7c/images/screenshot_66925.png -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=TFTShape 2 | version=1.0.0 3 | author=androdlang 4 | maintainer=androdlang 5 | sentence=A 2D graphics library for ESP8266 and ESP32 processors for the Arduino IDE 6 | paragraph=A 2D graphics library for ESP8266 and ESP32 processors for the Arduino IDE supporting Bodmers TFT_eSPI Driver. 7 | category=Display 8 | url=https://github.com/androdlang/TFTShape 9 | architectures=esp8266,esp32 10 | includes=TFTShape.h 11 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # TFTShape 2 | TFTShape is a 2D graphics library designed to work with the [Bodmer/TFT_eSPI](https://github.com/Bodmer/TFT_eSPI) library which supports SPI-TFT-displays for ESP8266/ESP32 processors. This library is abstracting low level primitives (pixels, lines) to bring them together for use as shape-based 2D drawing functions. It was developed to have an efficient implementation with a low footprint to run with best performance on the target processors. TFTShape has successfully been tested on an ODROID-GO (ILI9341 and ESP32@150MHz Wrover inside). 3 | 4 | TFTShape uses, as the name states, a shape based concept. Shapes are containers for groups of vertices which will be interpreted mostly as closed polygons, but depending on the used shape, the vertices can also be single points, open polygons or independent lines. Shapes have all common 2D drawing functions implemented, this includes sizing, translation, rotation, setting a pivot point and filling functions. Shapes can also be used to draw another shape at the position of the parent shape's vertices (grouping). 5 | 6 | Following classes and subclasses are available: 7 | * TFTShape - represents points and closed lines (polygons) 8 | * TFTLineShape - represents individual lines 9 | * TFTSplineShape - represents points interpreted as B-splines (open and looped splines) 10 | * TFTLinestripShape - represent contiguous lines (not closed) 11 | * TFTShapeBuilder - Factory to create special shapes, ie. grids,splines,stars, n-gons etc. 12 | 13 | To have an overview about the various output this library can produce, here are screenshots from the testsuite of the examples directory: 14 | 15 | ![screenshot_20293.png](/images/screenshot_20293.png) ![screenshot_35854.png](/images/screenshot_35854.png)![screenshot_4572.png](/images/screenshot_4572.png) ![screenshot_66902.png](/images/screenshot_66902.png) ![screenshot_20320.png](/images/screenshot_20320.png) ![screenshot_4554.png](/images/screenshot_4554.png) ![screenshot_4598.png](/images/screenshot_4598.png) ![screenshot_66925.png](/images/screenshot_66925.png) ![screenshot_20260.png](/images/screenshot_20260.png) ![screenshot_35807.png](/images/screenshot_35807.png) ![screenshot_4559.png](/images/screenshot_4559.png) ![screenshot_51345.png](/images/screenshot_51345.png) ![screenshot_20266.png](/images/screenshot_20266.png) ![screenshot_35845.png](/images/screenshot_35845.png) ![screenshot_4564.png](/images/screenshot_4564.png) ![screenshot_51372.png](/images/screenshot_51372.png) ![screenshot_20287.png](/images/screenshot_20287.png) ![screenshot_35853.png](/images/screenshot_35853.png) ![screenshot_4571.png](/images/screenshot_4571.png) ![screenshot_51387.png](/images/screenshot_51387.png) 16 | 17 | ## installation 18 | * Install [Bodmer/TFT_eSPI](https://github.com/Bodmer/TFT_eSPI) library and make sure examples are running. 19 | * Download zip and move extraced directory to the arduino libraries folder or use the Library Manager and select `install from zip` 20 | ## test 21 | * From the arduino file menu select examples TFTShape 22 | -------------------------------------------------------------------------------- /src/TFTLineShape.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #include "TFTShape.h" 7 | void TFTLineShape::draw(TFT_eSPI* display, int x0, int y0, int16_t color) { 8 | VEC2 *v=vertices; 9 | for(int i=0;i verts) { 12 | numVerts=verts.size(); 13 | vertices = new VEC2[numVerts]; 14 | std::copy(verts.begin(), verts.end(), vertices); 15 | } 16 | 17 | TFTLineShape() {} 18 | virtual void draw(TFT_eSPI* display, int x0, int y0, int16_t color); 19 | }; 20 | #endif -------------------------------------------------------------------------------- /src/TFTLinestripShape.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #include "TFTShape.h" 7 | void TFTLinestripShape::draw(TFT_eSPI* display, int x0, int y0, int16_t color) { 8 | VEC2 *v=vertices; 9 | for(int i=0,j=1;i= 1 ? p1 - 1 : numPoints - 1; 33 | } 34 | 35 | t = t - (int)t; 36 | //Serial.println(t); 37 | // Serial.printf("%d %d %d %d ",p0,p1,p2,p3);Serial.println(t); 38 | float tt = t * t; 39 | float ttt = tt * t; 40 | 41 | float q1 = -ttt + 2.0f*tt - t; 42 | float q2 = 3.0f*ttt - 5.0f*tt + 2.0f; 43 | float q3 = -3.0f*ttt + 4.0f*tt + t; 44 | float q4 = ttt - tt; 45 | 46 | float tx = 0.5f * (points[p0].x * q1 + points[p1].x * q2 + points[p2].x * q3 + points[p3].x * q4); 47 | float ty = 0.5f * (points[p0].y * q1 + points[p1].y * q2 + points[p2].y * q3 + points[p3].y * q4); 48 | //Serial.printf("%d %d %d\n",(int)ttt*100,(int)tx,(int)ty); 49 | return{ tx, ty }; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/TFTLinestripShape.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #ifndef TFTLSSHAPE_H 7 | #define TFTLSSHAPE_H 8 | 9 | class TFTLinestripShape :public TFTShape{ 10 | public: 11 | TFTLinestripShape(std::initializer_list verts) { 12 | numVerts=verts.size(); 13 | vertices = new VEC2[numVerts]; 14 | std::copy(verts.begin(), verts.end(), vertices); 15 | } 16 | TFTLinestripShape(VEC2*buffer,int n) { 17 | numVerts=n; 18 | vertices = new VEC2[numVerts]; 19 | memcpy(vertices,buffer,sizeof(VEC2)*numVerts); 20 | } 21 | void addPoints(std::initializer_list verts) { 22 | VEC2 *newVerts= new VEC2[numVerts+verts.size()]; 23 | memcpy(newVerts,vertices,sizeof(VEC2)*numVerts); 24 | std::copy(verts.begin(), verts.end(), &newVerts[numVerts]); 25 | delete[] vertices; 26 | vertices=newVerts; 27 | numVerts=numVerts+verts.size(); 28 | } 29 | TFTLinestripShape() {} 30 | virtual void draw(TFT_eSPI* display, int x0, int y0, int16_t color); 31 | static VEC2 getSplinePoint(VEC2* points, int numPoints,float t, bool bLooped = false); 32 | 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/TFTShape.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #include "TFTShape.h" 7 | #ifdef DEBUG 8 | void TFTShape::dumpVerts() { 9 | Serial.printf("Vertices in buffer:%d\n",numVerts); 10 | for(int i=0,j=1;ix = v.x; 78 | this->y = v.y; 79 | return *this; 80 | } 81 | TFTShape::TFTShape(std::initializer_list verts):numVerts(verts.size()) { 82 | vertices = new VEC2[numVerts]; 83 | std::copy(verts.begin(), verts.end(), vertices); 84 | } 85 | TFTShape::TFTShape(){ 86 | } 87 | TFTShape::~TFTShape() { 88 | //Serial.println(esp_get_free_heap_size()); 89 | 90 | if(vertices!=NULL) { 91 | //Serial.println("DESTRUCTOR vertices!!!!"); 92 | delete vertices; 93 | vertices=NULL; 94 | } 95 | //Serial.println(esp_get_free_heap_size()); 96 | 97 | } 98 | void TFTShape::setPivot(int x,int y) { 99 | pivot.x=x; pivot.y=y; 100 | } 101 | void TFTShape::setRotation(float a) { 102 | rotation=a; 103 | //ca=cos(rotation*M_PI/180); 104 | //sa=sin(rotation*M_PI/180); 105 | 106 | sincos.x=sin(rotation*M_PI/180); 107 | sincos.y=cos(rotation*M_PI/180); 108 | 109 | } 110 | void TFTShape::setRotationBy(float a) { 111 | rotation+=a; 112 | sincos.x=sin(rotation*M_PI/180); 113 | sincos.y=cos(rotation*M_PI/180); 114 | } 115 | float TFTShape::getRotation() { 116 | return rotation; 117 | } 118 | void TFTShape::setRotationFixed(bool b) { 119 | rotationFixed=b; 120 | } 121 | bool TFTShape::isRotationFixed() { 122 | return rotationFixed; 123 | } 124 | void TFTShape::setScale(float sx, float sy) { 125 | scalefac.x=sx; scalefac.y=sy; 126 | } 127 | void TFTShape::setScale(float s) { 128 | scalefac.x=scalefac.y=s; 129 | } 130 | void TFTShape::setScaleBy(float s) { 131 | scalefac.x*=s; 132 | scalefac.y*=s; 133 | } 134 | VEC2 TFTShape::getScale() { 135 | return scalefac; 136 | } 137 | void TFTShape::setOffset(float x, float y) { 138 | offset.x=x;offset.y=y; 139 | } 140 | VEC2 TFTShape::getOffset() { 141 | return offset; 142 | } 143 | void TFTShape::drawOptimizedLine(TFT_eSPI*display,int x,int y,int x0,int y0, int x1,int y1, int textcolor) { 144 | display->drawLine(x+x0,y+y0,x+x1,y+y1,textcolor); 145 | } 146 | void TFTShape::draw(TFT_eSPI* display, int x0, int y0, int16_t color) { 147 | int n=numVerts; 148 | VEC2 *v=vertices; 149 | for(int i=0,j=1;i=0) { 171 | c=CR::colorFromHSV(map(i,0,numVerts,color.from,color.to),1,1); 172 | } 173 | s.draw(display,x0+vi.x,y0+vi.y,c); 174 | } 175 | s.setRotation(originalRotation); 176 | } 177 | void TFTShape::fill(TFT_eSPI* display, int x0, int y0, TFTShape& s, const CR & color,int every) { 178 | VEC2 *v=vertices; 179 | float originalRotation=s.getRotation(); 180 | for(int i=0,j=1;i=0) { 193 | c=CR::colorFromHSV(map(i,0,numVerts,color.from,color.to),1,1); 194 | } 195 | s.fill(display,x0+vi.x,y0+vi.y,c,every); 196 | } 197 | s.setRotation(originalRotation); 198 | } 199 | void TFTShape::fillDraw(TFT_eSPI* display, int x0, int y0,TFTShape & s, const CR & colorOutline, const CR & color,int every) { 200 | fill(display,x0,y0,s,color,every); 201 | draw(display,x0,y0,s,colorOutline); 202 | } 203 | void TFTShape::fillH(TFT_eSPI* display, int x0, int y0, const CR & color,int every) { 204 | int16_t n=numVerts; 205 | VEC2 *v=vertices; 206 | 207 | int16_t minx, maxx; 208 | int x1, y1; 209 | int x2, y2; 210 | int16_t ix; 211 | 212 | int polyints[n]; 213 | //create a copy 214 | VEC2 vv[n]; 215 | 216 | // find y-min/max and transform vertices 217 | vv[0]=TRANSFORM(v[0]); 218 | minx = vv[0].x; 219 | maxx = vv[0].x; 220 | for (int i=1; (i < n); i++) 221 | { 222 | vv[i]=TRANSFORM(v[i]); 223 | minx = min(minx, vv[i].x); 224 | maxx = max(maxx, vv[i].x); 225 | 226 | } 227 | 228 | //scan y lines 229 | for(int scanline=minx; (scanline <= maxx); scanline++) { 230 | if(scanline%every) continue; 231 | ix = 0; 232 | for (int i=0,ii=n-1; (i < n); i++,ii=i-1) { 233 | x1 = vv[ii].x; //A 234 | x2 = vv[i].x; //B 235 | if(x1 == x2) continue; 236 | if (x1 < x2) { 237 | y1 = vv[ii].y; //a 238 | y2 = vv[i].y; //b 239 | } else { 240 | y1 = vv[i].y; //b 241 | y2 = vv[ii].y; //a 242 | x1 = vv[i].x; //B 243 | x2 = vv[ii].x; //A 244 | } 245 | if ((scanline >= x1) && (scanline < x2)) { 246 | polyints[ix++] = (scanline-x1) * (y2-y1) / (x2-x1) + y1; 247 | } else if ((scanline == maxx) && (scanline > x1) && (scanline <= x2)) { 248 | polyints[ix++] = (scanline-x1) * (y2-y1) / (x2-x1) + y1; 249 | } 250 | } 251 | qsort(polyints, ix, sizeof(int), [](const void *a, const void *b){return (*(const int *)a) - (*(const int *)b);}); 252 | uint16_t c=color.c; 253 | if(color.from>=0) { 254 | c=CR::colorFromHSV(map(scanline,minx,maxx,color.from,color.to),1,1); 255 | } 256 | for (int i=0; idrawFastVLine(x0+scanline,y0+polyints[i], polyints[i+1]- polyints[i],c); 258 | } 259 | } 260 | } 261 | void TFTShape::fillDraw(TFT_eSPI* display, int x0, int y0, const CR & colorOutline,CR color,int every) { 262 | fill(display,x0,y0,color,every); 263 | draw(display,x0,y0,colorOutline.c); 264 | } 265 | void TFTShape::fillDrawH(TFT_eSPI* display, int x0, int y0, const CR & colorOutline,CR color,int every) { 266 | fillH(display,x0,y0,color,every); 267 | draw(display,x0,y0,colorOutline.c); 268 | } 269 | void TFTShape::fill(TFT_eSPI* display, int x0, int y0, CR color,int every) { 270 | int16_t n=numVerts; 271 | VEC2 *v=vertices; 272 | 273 | int16_t miny, maxy; 274 | int x1, y1; 275 | int x2, y2; 276 | int16_t ix; 277 | 278 | int polyints[n]; 279 | //create a copy 280 | VEC2 vv[n]; 281 | 282 | // find y-min/max and transform vertices 283 | vv[0]=TRANSFORM(v[0]); 284 | miny = vv[0].y; 285 | maxy = vv[0].y; 286 | for (int i=1; (i < n); i++) 287 | { 288 | vv[i]=TRANSFORM(v[i]); 289 | miny = min(miny, vv[i].y); 290 | maxy = max(maxy, vv[i].y); 291 | 292 | } 293 | 294 | //scan y lines 295 | for(int scanline=miny; (scanline <= maxy); scanline++) { 296 | if(scanline%every) continue; 297 | ix = 0; 298 | for (int i=0,ii=n-1; (i < n); i++,ii=i-1) { 299 | y1 = vv[ii].y; //A 300 | y2 = vv[i].y; //B 301 | if(y1 == y2) continue; 302 | if (y1 < y2) { 303 | x1 = vv[ii].x; //a 304 | x2 = vv[i].x; //b 305 | } else { 306 | x1 = vv[i].x; //b 307 | x2 = vv[ii].x; //a 308 | y1 = vv[i].y; //B 309 | y2 = vv[ii].y; //A 310 | } 311 | if ((scanline >= y1) && (scanline < y2)) { 312 | polyints[ix++] = (scanline-y1) * (x2-x1) / (y2-y1) + x1; 313 | } else if ((scanline == maxy) && (scanline > y1) && (scanline <= y2)) { 314 | polyints[ix++] = (scanline-y1) * (x2-x1) / (y2-y1) + x1; 315 | } 316 | } 317 | qsort(polyints, ix, sizeof(int), [](const void *a, const void *b){return (*(const int *)a) - (*(const int *)b);}); 318 | // int16_t==slower !!! qsort(polyints, ix, sizeof(int16_t), [](const void *a, const void *b){return (*(const int16_t *)a) - (*(const int16_t *)b);}); 319 | uint16_t c=color.c; 320 | if(color.from>=0) { 321 | c=CR::colorFromHSV(map(scanline,miny,maxy,color.from,color.to),1,1); 322 | } 323 | 324 | for (int i=0; idrawFastHLine(x0+polyints[i],y0+scanline, polyints[i+1]- polyints[i],c); 326 | } 327 | } 328 | } 329 | VEC2 TFTShape::trans(VEC2 aa) { 330 | 331 | VEC2 a=aa; 332 | a+=offset; 333 | a-=pivot; 334 | a*=scalefac; 335 | a.rotate(sincos); 336 | a+=pivot; 337 | return a; 338 | } 339 | 340 | 341 | 342 | -------------------------------------------------------------------------------- /src/TFTShape.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #ifndef TFTSHAPE_H 7 | #define TFTSHAPE_H 8 | 9 | 10 | #include 11 | 12 | 13 | #define min(a,b)(ab?a:b) 15 | namespace tftshape { 16 | // #define min(a,b)(ab?a:b) 18 | } 19 | #define DEBUG 20 | 21 | #define CC_String(d,s,y,f,fg){d.setTextDatum(CC_DATUM);d.setTextColor(fg);d.drawString(s,d.width()/2,d.height()/2+y,f);} 22 | #define CC_StringB(d,s,y,f,fg,bg){d.setTextDatum(CC_DATUM);d.setTextColor(fg,bg);d.drawString(s,d.width()/2,d.height()/2+y,f);} 23 | #define BC_String(d,s,y,f,fg){d.setTextDatum(BC_DATUM);d.setTextColor(fg);d.drawString(s,d.width()/2,d.height()-y,f);} 24 | #define BC_StringB(d,s,y,f,fg,bg){d.setTextDatum(BC_DATUM);d.setTextColor(fg,bg);d.drawString(s,d.width()/2,d.height()-y,f);} 25 | #define TC_String(d,s,y,f,fg){d.setTextDatum(TC_DATUM);d.setTextColor(fg);d.drawString(s,d.width()/2,y,f);} 26 | #define TC_StringB(d,s,y,f,fg,bg){d.setTextDatum(TC_DATUM);d.setTextColor(fg,bg);d.drawString(s,d.width()/2,y,f);} 27 | const uint16_t PROGMEM rgb320s1v1[] = { 28 | 0xf800,0xf820,0xf840,0xf860,0xf880,0xf8a0,0xf8c0,0xf8e0,0xf920,0xf940,0xf960,0xf980,0xf9a0,0xf9c0,0xf9e0,0xfa20,0xfa60, 29 | 0xfa80,0xfaa0,0xfac0,0xfae0,0xfb00,0xfb20,0xfb40,0xfb80,0xfba0,0xfbc0,0xfbe0,0xfc20,0xfc40,0xfc60,0xfc80,0xfcc0,0xfce0, 30 | 0xfd00,0xfd20,0xfd40,0xfd60,0xfd80,0xfda0,0xfde0,0xfe20,0xfe40,0xfe60,0xfe80,0xfea0,0xfec0,0xfee0,0xff20,0xff40,0xff60, 31 | 0xff80,0xffa0,0xffc0,0xffe0,0xffe0,0xf7e0,0xefe0,0xefe0,0xe7e0,0xe7e0,0xdfe0,0xdfe0,0xd7e0,0xcfe0,0xcfe0,0xc7e0,0xbfe0, 32 | 0xbfe0,0xb7e0,0xb7e0,0xafe0,0xa7e0,0xa7e0,0x9fe0,0x9fe0,0x97e0,0x97e0,0x8fe0,0x8fe0,0x7fe0,0x7fe0,0x77e0,0x77e0,0x6fe0, 33 | 0x6fe0,0x67e0,0x67e0,0x5fe0,0x57e0,0x57e0,0x4fe0,0x4fe0,0x47e0,0x3fe0,0x3fe0,0x37e0,0x2fe0,0x2fe0,0x27e0,0x27e0,0x1fe0, 34 | 0x1fe0,0x17e0,0x0fe0,0x0fe0,0x07e0,0x07e0,0x07e0,0x07e1,0x07e1,0x07e2,0x07e2,0x07e3,0x07e4,0x07e4,0x07e5,0x07e5,0x07e6, 35 | 0x07e6,0x07e7,0x07e8,0x07e9,0x07e9,0x07ea,0x07ea,0x07eb,0x07eb,0x07ec,0x07ed,0x07ed,0x07ee,0x07ee,0x07ef,0x07ef,0x07f0, 36 | 0x07f1,0x07f2,0x07f2,0x07f3,0x07f3,0x07f4,0x07f4,0x07f5,0x07f6,0x07f6,0x07f7,0x07f7,0x07f8,0x07f9,0x07f9,0x07fa,0x07fb, 37 | 0x07fb,0x07fc,0x07fc,0x07fd,0x07fd,0x07fe,0x07fe,0x07ff,0x07df,0x07bf,0x079f,0x077f,0x075f,0x073f,0x071f,0x06df,0x06bf, 38 | 0x069f,0x067f,0x065f,0x063f,0x05ff,0x05df,0x059f,0x057f,0x055f,0x053f,0x051f,0x04ff,0x04df,0x04bf,0x049f,0x045f,0x043f, 39 | 0x03ff,0x03df,0x03bf,0x039f,0x037f,0x033f,0x031f,0x02ff,0x02df,0x02bf,0x029f,0x027f,0x025f,0x01ff,0x01df,0x01bf,0x019f, 40 | 0x017f,0x015f,0x013f,0x011f,0x00df,0x00bf,0x009f,0x007f,0x005f,0x003f,0x001f,0x001f,0x081f,0x101f,0x101f,0x181f,0x181f, 41 | 0x201f,0x201f,0x281f,0x281f,0x301f,0x381f,0x381f,0x401f,0x481f,0x481f,0x501f,0x581f,0x581f,0x601f,0x601f,0x681f,0x681f, 42 | 0x701f,0x701f,0x781f,0x801f,0x881f,0x881f,0x901f,0x901f,0x981f,0x981f,0xa01f,0xa81f,0xa81f,0xb01f,0xb01f,0xb81f,0xb81f, 43 | 0xc01f,0xc81f,0xd01f,0xd01f,0xd81f,0xd81f,0xe01f,0xe01f,0xe81f,0xf01f,0xf01f,0xf81f,0xf81f,0xf81f,0xf81e,0xf81e,0xf81d, 44 | 0xf81c,0xf81c,0xf81b,0xf81b,0xf81a,0xf81a,0xf819,0xf819,0xf817,0xf817,0xf816,0xf816,0xf815,0xf815,0xf814,0xf814,0xf813, 45 | 0xf812,0xf812,0xf811,0xf811,0xf810,0xf80f,0xf80f,0xf80e,0xf80d,0xf80d,0xf80c,0xf80c,0xf80b,0xf80b,0xf80a,0xf809,0xf809, 46 | 0xf808,0xf807,0xf807,0xf806,0xf806,0xf805,0xf804,0xf804,0xf803,0xf803,0xf802,0xf802,0xf801,0xf801}; 47 | 48 | 49 | #define TRANSFORM(a)trans(a); 50 | 51 | struct CR{ 52 | uint16_t c; 53 | int16_t from=-1; 54 | int16_t to=-1; 55 | CR(uint16_t color); 56 | CR(int16_t f,int16_t t); 57 | static void HSVtoRGB(float& fR, float& fG, float& fB, float& fH, float& fS, float& fV); 58 | static void RGBtoBW(float& fR, float& fG, float& fB, float& fH, float& fS, float& fV); 59 | static uint16_t colorFromHSV(int16_t hue,float s, float v); 60 | }; 61 | 62 | struct VEC2; 63 | struct VEC2 { 64 | float x; 65 | float y; 66 | VEC2(); 67 | VEC2(float a, float b); 68 | VEC2(float ab); 69 | void operator*=(const VEC2& b); 70 | void operator+=(const VEC2& b); 71 | void operator-=(const VEC2& b); 72 | void rotate(const VEC2& b); 73 | VEC2 &operator=(const VEC2 &v); 74 | }; 75 | 76 | 77 | 78 | class TFTShape { 79 | 80 | VEC2 pivot; //pivot point for scaling and rotation 81 | VEC2 scalefac=VEC2(1,1); //scale 82 | VEC2 offset; //relative offset of vertices 83 | float rotation=0; //rotation degrees 84 | bool rotationFixed=false; //if false: head to pivot of parent shape 85 | VEC2 sincos=VEC2(sin(rotation*M_PI/180),cos(rotation*M_PI/180)); //updated on every rotation change 86 | protected: 87 | friend class TFTShapeBuilder; 88 | VEC2 *vertices=NULL; //vertices buffer 89 | int numVerts; //number of vertices 90 | void drawOptimizedLine(TFT_eSPI*display,int x,int y,int x0,int y0, int x1,int y1, int textcolor); 91 | VEC2 trans(VEC2 a); //transpose function 92 | public: 93 | TFTShape(std::initializer_list verts); 94 | TFTShape(); 95 | TFTShape( VEC2 * buffer, int numVerts); 96 | void setPivot(int,int); 97 | void setRotation(float a); 98 | void setRotationBy(float a); 99 | float getRotation(); 100 | void setRotationFixed(bool b); 101 | bool isRotationFixed(); 102 | void setScale(float sx, float sy); 103 | void setScale(float s); 104 | void setScaleBy(float s); 105 | VEC2 getScale(); 106 | void setOffset(float sx, float sy); 107 | VEC2 getOffset(); 108 | void reset() {setOffset(0,0);setScale(1);setRotation(0);} 109 | VEC2 * getPoints() {return vertices;} 110 | int getNumPoints() {return numVerts;} 111 | TFTShape * scale(float s) {setScale(s); return this;} 112 | TFTShape * scaleBy(float s) {setScaleBy(s); return this;} 113 | TFTShape * rotate(float deg) {setRotation(deg); return this;} 114 | TFTShape * rotateBy(float deg) {setRotationBy(deg); return this;} 115 | TFTShape * spivot(int x,int y) {setPivot(x,y); return this;} 116 | virtual void draw(TFT_eSPI* display, int x0, int y0, int16_t color); 117 | void draw(TFT_eSPI* display, int x0, int y0, TFTShape &, const CR & color,int every=1); 118 | void fill(TFT_eSPI* display, int x0, int y0, CR color,int every=1); 119 | void fill(TFT_eSPI* display, int x0, int y0,TFTShape &, const CR & color,int every=1); 120 | void fillH(TFT_eSPI* display, int x0, int y0,const CR & color,int every=1); 121 | void fillDraw(TFT_eSPI* display, int x0, int y0,const CR & colorOutline, CR color,int every=1); 122 | void fillDraw(TFT_eSPI* display, int x0, int y0,TFTShape &, const CR & colorOutline, const CR & color,int every=1); 123 | void fillDrawH(TFT_eSPI* display, int x0, int y0,const CR & colorOutline, CR color,int every=1); 124 | void fillDrawH(TFT_eSPI* display, int x0, int y0,TFTShape &, const CR & colorOutline, const CR & color,int every=1); 125 | 126 | #ifdef DEBUG 127 | void dumpVerts(); 128 | #endif 129 | ~TFTShape(); 130 | 131 | }; 132 | #include "TFTLinestripShape.h" 133 | #include "TFTSplineShape.h" 134 | #include "TFTLineShape.h" 135 | #include "TFTShapeBuilder.h" 136 | #include "TFTSimplexNoise.h" 137 | #endif 138 | -------------------------------------------------------------------------------- /src/TFTShapeBuilder.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #include "TFTShape.h" 7 | 8 | void TFTShapeBuilder::fillNgonVertices(VEC2 *v ,int corners, VEC2 radius) { 9 | float a=360/corners; 10 | for(int i=0;i=0;i--) { 152 | float al=start*M_PI/180+ a*i*M_PI/180; 153 | ngon.vertices[ix].x=sin(al)*r2; 154 | ngon.vertices[ix].y=-cos(al)*r2; 155 | ix++; 156 | } 157 | //ngon.vertices[ngon.numVerts-1].x=0; 158 | //ngon.vertices[ngon.numVerts-1].y=0; 159 | return ngon; 160 | } 161 | 162 | TFTShape TFTShapeBuilder::buildGrid(int columns, int rows,int w, int h, bool alternate) { 163 | TFTShape grid= TFTShape(); 164 | grid.numVerts=rows*columns; 165 | VEC2 *vertices = new VEC2[grid.numVerts]; //max possible verts 166 | grid.vertices=vertices; 167 | float w2=w/2.; float h2=h/2.; 168 | double xstep= 1.0*w/(columns-1);double ystep= 1.0*h/(rows-1); 169 | int ix=0,cnt=0; 170 | for(int y=0;y=grid.numVerts) break; 175 | cnt++; 176 | 177 | } 178 | ix++; 179 | 180 | } 181 | } 182 | if(alternate) grid.numVerts=cnt; //reduce count if alternate 183 | return grid; 184 | } 185 | 186 | TFTLineShape TFTShapeBuilder::buildLineGrid(int rows, int columns,int w, int h) { 187 | TFTLineShape grid= TFTLineShape(); 188 | grid.numVerts=2*((rows+1)+(columns+1)); 189 | VEC2 *vertices = new VEC2[grid.numVerts]; 190 | grid.vertices=vertices; 191 | double xstep= 1.0*w/rows;double ystep= 1.0*h/columns; 192 | float w2=w/2.; float h2=h/2.; 193 | int vc=0; 194 | for(int y=0;y<=columns;y++) { 195 | vertices[vc].x=0-w2; 196 | vertices[vc].y=y*ystep-h2; 197 | vc++; 198 | vertices[vc].x=w-w2; 199 | vertices[vc].y=y*ystep-h2; 200 | vc++; 201 | } 202 | for(int x=0;x<=rows;x++){ 203 | vertices[vc].y=0-h2; 204 | vertices[vc].x=x*xstep-w2; 205 | vc++; 206 | vertices[vc].x=x*xstep-w2; 207 | vertices[vc].y=h-h2; 208 | vc++; 209 | } 210 | return grid; 211 | } 212 | //range -128 to +128 213 | TFTShape TFTShapeBuilder::buildRandomPoints(int num){ 214 | TFTShape ngon= TFTShape(); 215 | ngon.numVerts=num; 216 | VEC2 *vertices = new VEC2[ngon.numVerts]; 217 | ngon.vertices=vertices; 218 | for(int i=0;i 25 | #include "Arduino.h" 26 | #include "TFTShape.h" 27 | 28 | // Private static member definitions 29 | const double TFTSimplexNoise::F2 = 0.5 * (sqrt( 3.0 ) - 1.0); 30 | const double TFTSimplexNoise::G2 = (3.0 - sqrt( 3.0 )) / 6.0; 31 | const uint8_t TFTSimplexNoise::p[256] = { 32 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69, 33 | 142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219, 34 | 203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175, 35 | 74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230, 36 | 220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76, 37 | 132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173, 38 | 186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206, 39 | 59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163, 40 | 70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232, 41 | 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162, 42 | 241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204, 43 | 176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141, 44 | 128,195,78,66,215,61,156,180 45 | }; 46 | const Grad TFTSimplexNoise::grad3[12] = { 47 | Grad(1,1,0),Grad(-1,1,0),Grad(1,-1,0),Grad(-1,-1,0),Grad(1,0,1), 48 | Grad(-1,0,1),Grad(1,0,-1),Grad(-1,0,-1),Grad(0,1,1),Grad(0,-1,1), 49 | Grad(0,1,-1),Grad(0,-1,-1) 50 | }; 51 | uint8_t TFTSimplexNoise::perm[512] = {0}; 52 | uint8_t TFTSimplexNoise::permMod12[512] = {0}; 53 | 54 | // Initialize permutaion arrays 55 | void TFTSimplexNoise::init() { 56 | for ( uint16_t i = 0; i < 512; ++i ) { 57 | perm[i] = p[i & 255]; 58 | permMod12[i] = static_cast(perm[i] % 12); 59 | } 60 | //delete[] &p; // lol what 61 | } 62 | 63 | // Fast floor 64 | int32_t TFTSimplexNoise::fastFloor( double x ) { 65 | int32_t xi = static_cast(x); 66 | return x < xi ? xi - 1 : xi; 67 | } 68 | 69 | double TFTSimplexNoise::dot( const Grad& g, double x, double y ) { 70 | return g.x * x + g.y * y; 71 | } 72 | 73 | // 2D TFTSimplexNoise noise 74 | double TFTSimplexNoise::noise( double xin, double yin ) { 75 | double s = (xin + yin) * F2; 76 | int32_t i = fastFloor( xin + s ); 77 | int32_t j = fastFloor( yin + s ); 78 | double t = (i + j) * G2; 79 | double x0 = xin - (i - t); 80 | double y0 = yin - (j - t); 81 | uint8_t i1 = 0, j1 = 1; 82 | if ( x0 > y0 ) { 83 | i1 = 1; 84 | j1 = 0; 85 | } 86 | double x1 = x0 - i1 + G2; 87 | double y1 = y0 - j1 + G2; 88 | double x2 = x0 - 1.0 + 2.0 * G2; 89 | double y2 = y0 - 1.0 + 2.0 * G2; 90 | uint8_t ii = i & 255; 91 | uint8_t jj = j & 255; 92 | uint8_t gi0 = permMod12[ii + perm[jj]]; 93 | uint8_t gi1 = permMod12[ii + i1 + perm[jj + j1]]; 94 | uint8_t gi2 = permMod12[ii + 1 + perm[jj + 1]]; 95 | double n0 = 0.0; 96 | double t0 = 0.5 - x0 * x0 - y0 * y0; 97 | if ( t0 >= 0.0 ) { 98 | t0 *= t0; 99 | n0 = t0 * t0 * dot( grad3[gi0], x0, y0 ); 100 | } 101 | double n1 = 0.0; 102 | double t1 = 0.5 - x1 * x1 - y1 * y1; 103 | if ( t1 >= 0.0 ) { 104 | t1 *= t1; 105 | n1 = t1 * t1 * dot( grad3[gi1], x1, y1 ); 106 | } 107 | double n2 = 0.0; 108 | double t2 = 0.5 - x2 * x2 - y2 * y2; 109 | if ( t2 >= 0.0 ) { 110 | t2 *= t2; 111 | n2 = t2 * t2 * dot( grad3[gi2], x2, y2 ); 112 | } 113 | return 70.0 * (n0 + n1 + n2); 114 | } -------------------------------------------------------------------------------- /src/TFTSimplexNoise.h: -------------------------------------------------------------------------------- 1 | /* 2 | =============================================================================== 3 | Ported the SimplexNoise algorithm from the C++ versions mentioned below 4 | to a reuseable Arduino Library. 5 | 6 | By Jordan Shaw / http://jordanshaw.com / 2017-02 7 | 8 | A C++ port of a speed-improved simplex noise algorithm for 2D in Java. 9 | Based on example code by Stefan Gustavson (stegu@itn.liu.se). 10 | Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). 11 | Better rank ordering method by Stefan Gustavson in 2012. 12 | C++ port and minor type and algorithm changes by Josh Koch (jdk1337@gmail.com). 13 | This could be speeded up even further, but it's useful as it is. 14 | Version 2012-04-12 15 | The original Java code was placed in the public domain by its original author, 16 | Stefan Gustavson. You may use it as you see fit, 17 | but attribution is appreciated. 18 | 19 | Original gist url: https://gist.github.com/Slipyx/2372043 20 | 21 | =============================================================================== 22 | */ 23 | 24 | #ifndef SimplexNoise_h 25 | #define SimplexNoise_h 26 | 27 | #include 28 | #include "Arduino.h" 29 | 30 | class Grad { 31 | public: 32 | Grad( int8_t x, int8_t y, int8_t z ) : x(x), y(y), z(z) {} 33 | int8_t x, y, z; 34 | }; 35 | 36 | class TFTSimplexNoise { 37 | public: 38 | // Initialize permutation arrays 39 | static void init(); 40 | // 2D simplex noise 41 | static double noise( double xin, double yin ); 42 | 43 | private: 44 | static int32_t fastFloor( double x ); 45 | static double dot( const Grad& g, double x, double y ); 46 | static const double F2; 47 | static const double G2; 48 | static const Grad grad3[12]; 49 | static const uint8_t p[256]; 50 | static uint8_t perm[512]; 51 | static uint8_t permMod12[512]; 52 | 53 | }; 54 | 55 | #endif -------------------------------------------------------------------------------- /src/TFTSplineShape.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | Arduino TFT 2D graphics library targeted at ESP8266 3 | and ESP32 based boards using the TFT_eSPI library (https://github.com/Bodmer/TFT_eSPI). 4 | created by JLA 11/2018 (https://github.com/androdlang/TFTShape). 5 | ****************************************************/ 6 | #ifndef TFT_SPLINESHAPE 7 | #define TFT_SPLINESHAPE 8 | 9 | class TFTSplineShape:public TFTLinestripShape { 10 | int subSamples; 11 | int numSamples; 12 | bool isLooped; 13 | public: 14 | TFTSplineShape(int numsamples,int subsamples,bool islooped):isLooped(islooped),subSamples(subsamples),numSamples(numsamples) { 15 | numVerts=isLooped?(numSamples*subSamples):((numSamples-3)*subSamples+1); 16 | vertices = new VEC2[numVerts]; 17 | } 18 | 19 | TFTSplineShape(std::initializer_list samples,int subsamples,bool islooped):isLooped(islooped),subSamples(subsamples),numSamples(samples.size()) { 20 | numVerts=isLooped?(numSamples*subSamples):((numSamples-3)*subSamples+1); 21 | vertices = new VEC2[numVerts]; 22 | VEC2 buffer[samples.size()]; 23 | std::copy(samples.begin(), samples.end(), buffer); 24 | updateData(buffer); 25 | } 26 | 27 | TFTSplineShape(VEC2*samples,int numsamples,int subsamples,bool islooped):isLooped(islooped),subSamples(subsamples),numSamples(numsamples) { 28 | numVerts=isLooped?(numSamples*subSamples):((numSamples-3)*subSamples+1); 29 | vertices = new VEC2[numVerts]; 30 | updateData(samples); 31 | } 32 | 33 | void updateData(VEC2*samples) { 34 | int ix=0; 35 | float fstep=1./subSamples; 36 | if(isLooped) { 37 | for (float t = 0; t < (float)(numSamples); t += fstep) { 38 | if(ix