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

Demo_3D_cube.ino (7463B)

      1 /*
      2 
      3  Example sketch for TFT_eSPI library.
      4 
      5  No fonts are needed.
      6  
      7  Draws a 3d rotating cube on the TFT screen.
      8  
      9  Original code was found at http://forum.freetronics.com/viewtopic.php?f=37&t=5495
     10  
     11  */
     12 
     13 #define BLACK 0x0000
     14 #define WHITE 0xFFFF
     15 
     16 #include <SPI.h>
     17 
     18 #include <TFT_eSPI.h> // Hardware-specific library
     19 
     20 TFT_eSPI tft = TFT_eSPI();       // Invoke custom library
     21 
     22 int16_t h;
     23 int16_t w;
     24 
     25 int inc = -2;
     26 
     27 float xx, xy, xz;
     28 float yx, yy, yz;
     29 float zx, zy, zz;
     30 
     31 float fact;
     32 
     33 int Xan, Yan;
     34 
     35 int Xoff;
     36 int Yoff;
     37 int Zoff;
     38 
     39 struct Point3d
     40 {
     41   int x;
     42   int y;
     43   int z;
     44 };
     45 
     46 struct Point2d
     47 {
     48   int x;
     49   int y;
     50 };
     51 
     52 int LinestoRender; // lines to render.
     53 int OldLinestoRender; // lines to render just in case it changes. this makes sure the old lines all get erased.
     54 
     55 struct Line3d
     56 {
     57   Point3d p0;
     58   Point3d p1;
     59 };
     60 
     61 struct Line2d
     62 {
     63   Point2d p0;
     64   Point2d p1;
     65 };
     66 
     67 Line3d Lines[20];
     68 Line2d Render[20];
     69 Line2d ORender[20];
     70 
     71 /***********************************************************************************************************************************/
     72 void setup() {
     73 
     74   tft.init();
     75 
     76   h = tft.height();
     77   w = tft.width();
     78 
     79   tft.setRotation(1);
     80 
     81   tft.fillScreen(TFT_BLACK);
     82 
     83   cube();
     84 
     85   fact = 180 / 3.14159259; // conversion from degrees to radians.
     86 
     87   Xoff = 240; // Position the centre of the 3d conversion space into the centre of the TFT screen.
     88   Yoff = 160;
     89   Zoff = 550; // Z offset in 3D space (smaller = closer and bigger rendering)
     90 }
     91 
     92 /***********************************************************************************************************************************/
     93 void loop() {
     94 
     95   // Rotate around x and y axes in 1 degree increments
     96   Xan++;
     97   Yan++;
     98 
     99   Yan = Yan % 360;
    100   Xan = Xan % 360; // prevents overflow.
    101 
    102   SetVars(); //sets up the global vars to do the 3D conversion.
    103 
    104   // Zoom in and out on Z axis within limits
    105   // the cube intersects with the screen for values < 160
    106   Zoff += inc; 
    107   if (Zoff > 500) inc = -1;     // Switch to zoom in
    108   else if (Zoff < 160) inc = 1; // Switch to zoom out
    109 
    110   for (int i = 0; i < LinestoRender ; i++)
    111   {
    112     ORender[i] = Render[i]; // stores the old line segment so we can delete it later.
    113     ProcessLine(&Render[i], Lines[i]); // converts the 3d line segments to 2d.
    114   }
    115   RenderImage(); // go draw it!
    116 
    117   delay(14); // Delay to reduce loop rate (reduces flicker caused by aliasing with TFT screen refresh rate)
    118 }
    119 
    120 /***********************************************************************************************************************************/
    121 void RenderImage( void)
    122 {
    123   // renders all the lines after erasing the old ones.
    124   // in here is the only code actually interfacing with the OLED. so if you use a different lib, this is where to change it.
    125 
    126   for (int i = 0; i < OldLinestoRender; i++ )
    127   {
    128     tft.drawLine(ORender[i].p0.x, ORender[i].p0.y, ORender[i].p1.x, ORender[i].p1.y, BLACK); // erase the old lines.
    129   }
    130 
    131 
    132   for (int i = 0; i < LinestoRender; i++ )
    133   {
    134     uint16_t color = TFT_BLUE;
    135     if (i < 4) color = TFT_RED;
    136     if (i > 7) color = TFT_GREEN;
    137     tft.drawLine(Render[i].p0.x, Render[i].p0.y, Render[i].p1.x, Render[i].p1.y, color);
    138   }
    139   OldLinestoRender = LinestoRender;
    140 }
    141 
    142 /***********************************************************************************************************************************/
    143 // Sets the global vars for the 3d transform. Any points sent through "process" will be transformed using these figures.
    144 // only needs to be called if Xan or Yan are changed.
    145 void SetVars(void)
    146 {
    147   float Xan2, Yan2, Zan2;
    148   float s1, s2, s3, c1, c2, c3;
    149 
    150   Xan2 = Xan / fact; // convert degrees to radians.
    151   Yan2 = Yan / fact;
    152 
    153   // Zan is assumed to be zero
    154 
    155   s1 = sin(Yan2);
    156   s2 = sin(Xan2);
    157 
    158   c1 = cos(Yan2);
    159   c2 = cos(Xan2);
    160 
    161   xx = c1;
    162   xy = 0;
    163   xz = -s1;
    164 
    165   yx = (s1 * s2);
    166   yy = c2;
    167   yz = (c1 * s2);
    168 
    169   zx = (s1 * c2);
    170   zy = -s2;
    171   zz = (c1 * c2);
    172 }
    173 
    174 
    175 /***********************************************************************************************************************************/
    176 // processes x1,y1,z1 and returns rx1,ry1 transformed by the variables set in SetVars()
    177 // fairly heavy on floating point here.
    178 // uses a bunch of global vars. Could be rewritten with a struct but not worth the effort.
    179 void ProcessLine(struct Line2d *ret, struct Line3d vec)
    180 {
    181   float zvt1;
    182   int xv1, yv1, zv1;
    183 
    184   float zvt2;
    185   int xv2, yv2, zv2;
    186 
    187   int rx1, ry1;
    188   int rx2, ry2;
    189 
    190   int x1;
    191   int y1;
    192   int z1;
    193 
    194   int x2;
    195   int y2;
    196   int z2;
    197 
    198   int Ok;
    199 
    200   x1 = vec.p0.x;
    201   y1 = vec.p0.y;
    202   z1 = vec.p0.z;
    203 
    204   x2 = vec.p1.x;
    205   y2 = vec.p1.y;
    206   z2 = vec.p1.z;
    207 
    208   Ok = 0; // defaults to not OK
    209 
    210   xv1 = (x1 * xx) + (y1 * xy) + (z1 * xz);
    211   yv1 = (x1 * yx) + (y1 * yy) + (z1 * yz);
    212   zv1 = (x1 * zx) + (y1 * zy) + (z1 * zz);
    213 
    214   zvt1 = zv1 - Zoff;
    215 
    216   if ( zvt1 < -5) {
    217     rx1 = 256 * (xv1 / zvt1) + Xoff;
    218     ry1 = 256 * (yv1 / zvt1) + Yoff;
    219     Ok = 1; // ok we are alright for point 1.
    220   }
    221 
    222   xv2 = (x2 * xx) + (y2 * xy) + (z2 * xz);
    223   yv2 = (x2 * yx) + (y2 * yy) + (z2 * yz);
    224   zv2 = (x2 * zx) + (y2 * zy) + (z2 * zz);
    225 
    226   zvt2 = zv2 - Zoff;
    227 
    228   if ( zvt2 < -5) {
    229     rx2 = 256 * (xv2 / zvt2) + Xoff;
    230     ry2 = 256 * (yv2 / zvt2) + Yoff;
    231   } else
    232   {
    233     Ok = 0;
    234   }
    235 
    236   if (Ok == 1) {
    237 
    238     ret->p0.x = rx1;
    239     ret->p0.y = ry1;
    240 
    241     ret->p1.x = rx2;
    242     ret->p1.y = ry2;
    243   }
    244   // The ifs here are checks for out of bounds. needs a bit more code here to "safe" lines that will be way out of whack, so they don't get drawn and cause screen garbage.
    245 
    246 }
    247 
    248 /***********************************************************************************************************************************/
    249 // line segments to draw a cube. basically p0 to p1. p1 to p2. p2 to p3 so on.
    250 void cube(void)
    251 {
    252   // Front Face.
    253 
    254   Lines[0].p0.x = -50;
    255   Lines[0].p0.y = -50;
    256   Lines[0].p0.z = 50;
    257   Lines[0].p1.x = 50;
    258   Lines[0].p1.y = -50;
    259   Lines[0].p1.z = 50;
    260 
    261   Lines[1].p0.x = 50;
    262   Lines[1].p0.y = -50;
    263   Lines[1].p0.z = 50;
    264   Lines[1].p1.x = 50;
    265   Lines[1].p1.y = 50;
    266   Lines[1].p1.z = 50;
    267 
    268   Lines[2].p0.x = 50;
    269   Lines[2].p0.y = 50;
    270   Lines[2].p0.z = 50;
    271   Lines[2].p1.x = -50;
    272   Lines[2].p1.y = 50;
    273   Lines[2].p1.z = 50;
    274 
    275   Lines[3].p0.x = -50;
    276   Lines[3].p0.y = 50;
    277   Lines[3].p0.z = 50;
    278   Lines[3].p1.x = -50;
    279   Lines[3].p1.y = -50;
    280   Lines[3].p1.z = 50;
    281 
    282 
    283   //back face.
    284 
    285   Lines[4].p0.x = -50;
    286   Lines[4].p0.y = -50;
    287   Lines[4].p0.z = -50;
    288   Lines[4].p1.x = 50;
    289   Lines[4].p1.y = -50;
    290   Lines[4].p1.z = -50;
    291 
    292   Lines[5].p0.x = 50;
    293   Lines[5].p0.y = -50;
    294   Lines[5].p0.z = -50;
    295   Lines[5].p1.x = 50;
    296   Lines[5].p1.y = 50;
    297   Lines[5].p1.z = -50;
    298 
    299   Lines[6].p0.x = 50;
    300   Lines[6].p0.y = 50;
    301   Lines[6].p0.z = -50;
    302   Lines[6].p1.x = -50;
    303   Lines[6].p1.y = 50;
    304   Lines[6].p1.z = -50;
    305 
    306   Lines[7].p0.x = -50;
    307   Lines[7].p0.y = 50;
    308   Lines[7].p0.z = -50;
    309   Lines[7].p1.x = -50;
    310   Lines[7].p1.y = -50;
    311   Lines[7].p1.z = -50;
    312 
    313 
    314   // now the 4 edge lines.
    315 
    316   Lines[8].p0.x = -50;
    317   Lines[8].p0.y = -50;
    318   Lines[8].p0.z = 50;
    319   Lines[8].p1.x = -50;
    320   Lines[8].p1.y = -50;
    321   Lines[8].p1.z = -50;
    322 
    323   Lines[9].p0.x = 50;
    324   Lines[9].p0.y = -50;
    325   Lines[9].p0.z = 50;
    326   Lines[9].p1.x = 50;
    327   Lines[9].p1.y = -50;
    328   Lines[9].p1.z = -50;
    329 
    330   Lines[10].p0.x = -50;
    331   Lines[10].p0.y = 50;
    332   Lines[10].p0.z = 50;
    333   Lines[10].p1.x = -50;
    334   Lines[10].p1.y = 50;
    335   Lines[10].p1.z = -50;
    336 
    337   Lines[11].p0.x = 50;
    338   Lines[11].p0.y = 50;
    339   Lines[11].p0.z = 50;
    340   Lines[11].p1.x = 50;
    341   Lines[11].p1.y = 50;
    342   Lines[11].p1.z = -50;
    343 
    344   LinestoRender = 12;
    345   OldLinestoRender = LinestoRender;
    346 
    347 }
    348