PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

solid3D.ino 6.0KB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. From ucg, modified for use with all my libraries.
  3. IMPORTANT! You need my modified Adafruit_GFX library!
  4. https://github.com/sumotoy/Adafruit_GFX/
  5. */
  6. #include <SPI.h>
  7. #include <Adafruit_GFX.h>
  8. #include <TFT_ILI9163C.h>
  9. #ifndef _ADAFRUIT_GFX_VARIANT
  10. #error you need the modified Adafruit_GFX library!
  11. #endif
  12. #define __CS 10
  13. #define __DC 6
  14. TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC);
  15. struct pt3d
  16. {
  17. int x, y, z;
  18. };
  19. struct surface
  20. {
  21. uint8_t p[4];
  22. int16_t z;
  23. };
  24. struct pt2d
  25. {
  26. int x, y;
  27. unsigned is_visible;
  28. };
  29. // define the point at which the observer looks, 3d box will be centered there
  30. #define MX (tft.width()/2)
  31. #define MY (tft.height()/2)
  32. // define a value that corresponds to "1"
  33. #define U 100
  34. // eye to screen distance (fixed)
  35. #define ZS U
  36. // cube edge length is 2*U
  37. struct pt3d cube[8] =
  38. {
  39. { -U, -U, U},
  40. { U, -U, U},
  41. { U, -U, -U},
  42. { -U, -U, -U},
  43. { -U, U, U},
  44. { U, U, U},
  45. { U, U, -U},
  46. { -U, U, -U},
  47. };
  48. // define the surfaces
  49. struct surface cube_surface[6] =
  50. {
  51. { {0, 1, 2, 3}, 0 }, // bottom
  52. { {4, 5, 6, 7}, 0 }, // top
  53. { {0, 1, 5, 4}, 0 }, // back
  54. { {3, 7, 6, 2}, 0 }, // front
  55. { {1, 2, 6, 5}, 0 }, // right
  56. { {0, 3, 7, 4}, 0 }, // left
  57. };
  58. // define some structures for the copy of the box, calculation will be done there
  59. struct pt3d cube2[8];
  60. struct pt2d cube_pt[8];
  61. // will contain a rectangle border of the box projection into 2d plane
  62. int x_min, x_max;
  63. int y_min, y_max;
  64. const int16_t sin_tbl[65] = {
  65. 0, 1606, 3196, 4756, 6270, 7723, 9102, 10394, 11585, 12665, 13623, 14449, 15137, 15679, 16069, 16305, 16384, 16305, 16069, 15679,
  66. 15137, 14449, 13623, 12665, 11585, 10394, 9102, 7723, 6270, 4756, 3196, 1606, 0, -1605, -3195, -4755, -6269, -7722, -9101, -10393,
  67. -11584, -12664, -13622, -14448, -15136, -15678, -16068, -16304, -16383, -16304, -16068, -15678, -15136, -14448, -13622, -12664, -11584, -10393, -9101, -7722,
  68. -6269, -4755, -3195, -1605, 0
  69. };
  70. const int16_t cos_tbl[65] = {
  71. 16384, 16305, 16069, 15679, 15137, 14449, 13623, 12665, 11585, 10394, 9102, 7723, 6270, 4756, 3196, 1606, 0, -1605, -3195, -4755,
  72. -6269, -7722, -9101, -10393, -11584, -12664, -13622, -14448, -15136, -15678, -16068, -16304, -16383, -16304, -16068, -15678, -15136, -14448, -13622, -12664,
  73. -11584, -10393, -9101, -7722, -6269, -4755, -3195, -1605, 0, 1606, 3196, 4756, 6270, 7723, 9102, 10394, 11585, 12665, 13623, 14449,
  74. 15137, 15679, 16069, 16305, 16384
  75. };
  76. void copy_cube(void)
  77. {
  78. uint8_t i;
  79. for (i = 0; i < 8; i++)
  80. {
  81. cube2[i] = cube[i];
  82. }
  83. }
  84. void rotate_cube_y(uint16_t w)
  85. {
  86. uint8_t i;
  87. int16_t x, z;
  88. /*
  89. x' = x * cos(w) + z * sin(w)
  90. z' = - x * sin(w) + z * cos(w)
  91. */
  92. for (i = 0; i < 8; i++)
  93. {
  94. x = ((int32_t)cube2[i].x * (int32_t)cos_tbl[w] + (int32_t)cube2[i].z * (int32_t)sin_tbl[w]) >> 14;
  95. z = (-(int32_t)cube2[i].x * (int32_t)sin_tbl[w] + (int32_t)cube2[i].z * (int32_t)cos_tbl[w]) >> 14;
  96. //printf("%d: %d %d --> %d %d\n", i, cube2[i].x, cube2[i].z, x, z);
  97. cube2[i].x = x;
  98. cube2[i].z = z;
  99. }
  100. }
  101. void rotate_cube_x(uint16_t w)
  102. {
  103. uint8_t i;
  104. int16_t y, z;
  105. for (i = 0; i < 8; i++)
  106. {
  107. y = ((int32_t)cube2[i].y * (int32_t)cos_tbl[w] + (int32_t)cube2[i].z * (int32_t)sin_tbl[w]) >> 14;
  108. z = (-(int32_t)cube2[i].y * (int32_t)sin_tbl[w] + (int32_t)cube2[i].z * (int32_t)cos_tbl[w]) >> 14;
  109. cube2[i].y = y;
  110. cube2[i].z = z;
  111. }
  112. }
  113. void trans_cube(uint16_t z)
  114. {
  115. uint8_t i;
  116. for (i = 0; i < 8; i++)
  117. {
  118. cube2[i].z += z;
  119. }
  120. }
  121. void reset_min_max(void)
  122. {
  123. x_min = 0x07fff;
  124. y_min = 0x07fff;
  125. x_max = -0x07fff;
  126. y_max = -0x07fff;
  127. }
  128. // calculate xs and ys from a 3d value
  129. void convert_3d_to_2d(struct pt3d *p3, struct pt2d *p2)
  130. {
  131. int32_t t;
  132. p2->is_visible = 1;
  133. if (p3->z >= ZS)
  134. {
  135. t = ZS;
  136. t *= p3->x;
  137. t <<= 1;
  138. t /= p3->z;
  139. if (t >= -MX && t <= MX - 1)
  140. {
  141. t += MX;
  142. p2->x = t;
  143. if (x_min > t) x_min = t;
  144. if (x_max < t) x_max = t;
  145. t = ZS;
  146. t *= p3->y;
  147. t <<= 1;
  148. t /= p3->z;
  149. if (t >= -MY && t <= MY - 1)
  150. {
  151. t += MY;
  152. p2->y = t;
  153. if (y_min > t) y_min = t;
  154. if (y_max < t) y_max = t;
  155. }
  156. else
  157. {
  158. p2->is_visible = 0;
  159. }
  160. }
  161. else
  162. {
  163. p2->is_visible = 0;
  164. }
  165. }
  166. else
  167. {
  168. p2->is_visible = 0;
  169. }
  170. }
  171. void convert_cube(void)
  172. {
  173. uint8_t i;
  174. reset_min_max();
  175. for (i = 0; i < 8; i++)
  176. {
  177. convert_3d_to_2d(cube2 + i, cube_pt + i);
  178. }
  179. }
  180. void calculate_z(void)
  181. {
  182. uint8_t i, j;
  183. uint16_t z;
  184. for (i = 0; i < 6; i++)
  185. {
  186. z = 0;
  187. for (j = 0; j < 4; j++)
  188. {
  189. z += cube2[cube_surface[i].p[j]].z;
  190. }
  191. z /= 4;
  192. cube_surface[i].z = z;
  193. //printf("%d: z=%d\n", i, z);
  194. }
  195. }
  196. void draw_cube(void)
  197. {
  198. uint8_t i, ii;
  199. uint8_t skip_cnt = 3; /* it is known, that the first 3 surfaces are invisible */
  200. int16_t z, z_upper;
  201. uint16_t color;
  202. z_upper = 32767;
  203. for (;;)
  204. {
  205. ii = 6;
  206. z = -32767;
  207. for (i = 0; i < 6; i++)
  208. {
  209. if (cube_surface[i].z <= z_upper)
  210. {
  211. if (z < cube_surface[i].z)
  212. {
  213. z = cube_surface[i].z;
  214. ii = i;
  215. }
  216. }
  217. }
  218. if (ii >= 6) break;
  219. z_upper = cube_surface[ii].z;
  220. cube_surface[ii].z++;
  221. if (skip_cnt > 0)
  222. {
  223. skip_cnt--;
  224. }
  225. else
  226. {
  227. color = tft.Color565(((ii + 1) & 1) * 255, (((ii + 1) >> 1) & 1) * 255, (((ii + 1) >> 2) & 1) * 255);
  228. tft.fillQuad(
  229. cube_pt[cube_surface[ii].p[0]].x, cube_pt[cube_surface[ii].p[0]].y,
  230. cube_pt[cube_surface[ii].p[1]].x, cube_pt[cube_surface[ii].p[1]].y,
  231. cube_pt[cube_surface[ii].p[2]].x, cube_pt[cube_surface[ii].p[2]].y,
  232. cube_pt[cube_surface[ii].p[3]].x, cube_pt[cube_surface[ii].p[3]].y, color);
  233. }
  234. }
  235. }
  236. void calc_and_draw(uint16_t w, uint16_t v)
  237. {
  238. copy_cube();
  239. rotate_cube_y(w);
  240. rotate_cube_x(v);
  241. trans_cube(U * 8);
  242. convert_cube();
  243. calculate_z();
  244. draw_cube();
  245. }
  246. void setup(void)
  247. {
  248. tft.begin();
  249. }
  250. uint16_t w = 0;
  251. uint16_t v = 0;
  252. void loop(void)
  253. {
  254. calc_and_draw(w, v >> 3);
  255. v += 3;
  256. v &= 511;
  257. w++;
  258. w &= 63;
  259. delay(10);
  260. tft.fillRect(x_min, y_min, x_max - x_min + 3, y_max - y_min + 3, 0x0000);
  261. }