wireframe.ino 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include <SPI.h>
  2. #include <GD.h>
  3. ////////////////////////////////////////////////////////////////////////////////
  4. // Plotter
  5. ////////////////////////////////////////////////////////////////////////////////
  6. #include "wireframe.h"
  7. #include "eraser.h"
  8. // replicate a 2-bit color across the whole byte.
  9. byte replicate(byte color)
  10. {
  11. return (color << 6) | (color << 4) | (color << 2) | color;
  12. }
  13. #define BLACK RGB(0,0,0)
  14. #define WHITE RGB(255,255,255)
  15. class PlotterClass
  16. {
  17. public:
  18. void begin();
  19. void line(byte x0, byte y0, byte x1, byte y1);
  20. void show();
  21. private:
  22. byte flip;
  23. byte plotting;
  24. void erase();
  25. void waitready();
  26. };
  27. PlotterClass Plotter;
  28. void PlotterClass::waitready()
  29. {
  30. while (GD.rd(COMM+7))
  31. ;
  32. }
  33. void PlotterClass::erase()
  34. {
  35. byte color = flip ? 1 : 2;
  36. plotting = 0;
  37. GD.wr(J1_RESET, 1);
  38. GD.wr(COMM+7, 1);
  39. GD.wr(COMM+8, replicate(color ^ 3));
  40. GD.microcode(eraser_code, sizeof(eraser_code));
  41. }
  42. void PlotterClass::begin()
  43. {
  44. // Draw 256 sprites left to right, top to bottom, all in 4-color
  45. // palette mode. By doing them in column-wise order, the address
  46. // calculation in setpixel is made simpler.
  47. // First 64 use bits 0-1, next 64 use bits 2-4, etc.
  48. // This gives a 256 x 256 4-color bitmap.
  49. unsigned int i;
  50. for (i = 0; i < 256; i++) {
  51. int x = 72 + 16 * ((i >> 4) & 15);
  52. int y = 22 + 16 * (i & 15);
  53. int image = i & 63; /* image 0-63 */
  54. int pal = 3 - (i >> 6); /* palettes bits in columns 3,2,1,0 */
  55. GD.sprite(i, x, y, image, 0x8 | (pal << 1), 0);
  56. }
  57. flip = 0;
  58. plotting = 0;
  59. erase();
  60. show();
  61. }
  62. void PlotterClass::show()
  63. {
  64. waitready();
  65. if (flip == 1) {
  66. GD.wr16(PALETTE4A, BLACK);
  67. GD.wr16(PALETTE4A + 2, WHITE);
  68. GD.wr16(PALETTE4A + 4, BLACK);
  69. GD.wr16(PALETTE4A + 6, WHITE);
  70. } else {
  71. GD.wr16(PALETTE4A, BLACK);
  72. GD.wr16(PALETTE4A + 2, BLACK);
  73. GD.wr16(PALETTE4A + 4, WHITE);
  74. GD.wr16(PALETTE4A + 6, WHITE);
  75. }
  76. flip ^= 1;
  77. erase();
  78. }
  79. void PlotterClass::line(byte x0, byte y0, byte x1, byte y1)
  80. {
  81. byte swap;
  82. #define SWAP(a, b) (swap = (a), (a) = (b), (b) = swap)
  83. byte steep = abs(y1 - y0) > abs(x1 - x0);
  84. if (steep) {
  85. SWAP(x0, y0);
  86. SWAP(x1, y1);
  87. }
  88. if (x0 > x1) {
  89. SWAP(x0, x1);
  90. SWAP(y0, y1);
  91. }
  92. int deltax = x1 - x0;
  93. int deltay = abs(y1 - y0);
  94. int error = deltax / 2;
  95. char ystep;
  96. if (y0 < y1)
  97. ystep = 1;
  98. else
  99. ystep = -1;
  100. byte x;
  101. byte y = y0;
  102. waitready();
  103. if (!plotting) {
  104. GD.microcode(wireframe_code, sizeof(wireframe_code));
  105. plotting = 1;
  106. byte color = flip ? 1 : 2;
  107. GD.wr(COMM+8, color << 6);
  108. }
  109. GD.__wstart(COMM+0);
  110. SPI.transfer(x0);
  111. SPI.transfer(y0);
  112. SPI.transfer(x1);
  113. SPI.transfer(y1);
  114. SPI.transfer(steep);
  115. SPI.transfer(deltax);
  116. SPI.transfer(deltay);
  117. SPI.transfer(ystep);
  118. GD.__end();
  119. }
  120. ////////////////////////////////////////////////////////////////////////////////
  121. // 3D Projection
  122. ////////////////////////////////////////////////////////////////////////////////
  123. #include "eliteships.h"
  124. #define NSHIPS (sizeof(eliteships) / sizeof(eliteships[0]))
  125. static float mat[9];
  126. // Taken from glRotate()
  127. static void rotation(float phi)
  128. {
  129. float x = 0.57735026918962573;
  130. float y = 0.57735026918962573;
  131. float z = 0.57735026918962573;
  132. float s = sin(phi);
  133. float c = cos(phi);
  134. mat[0] = x*x*(1-c)+c;
  135. mat[1] = x*y*(1-c)-z*s;
  136. mat[2] = x*z*(1-c)+y*s;
  137. mat[3] = y*x*(1-c)+z*s;
  138. mat[4] = y*y*(1-c)+c;
  139. mat[5] = y*z*(1-c)-x*s;
  140. mat[6] = x*z*(1-c)-y*s;
  141. mat[7] = y*z*(1-c)+x*s;
  142. mat[8] = z*z*(1-c)+c;
  143. }
  144. static byte projected[40 * 2];
  145. void project(struct ship *s, float distance)
  146. {
  147. byte vx;
  148. flash_int8_t *pm = s->vertices;
  149. flash_int8_t *pm_e = pm + (s->nvertices * 3);
  150. byte *dst = projected;
  151. char x, y, z;
  152. while (pm < pm_e) {
  153. x = pgm_read_byte_near(pm++);
  154. y = pgm_read_byte_near(pm++);
  155. z = pgm_read_byte_near(pm++);
  156. float xx = x * mat[0] + y * mat[3] + z * mat[6];
  157. float yy = x * mat[1] + y * mat[4] + z * mat[7];
  158. float zz = x * mat[2] + y * mat[5] + z * mat[8] + distance;
  159. float q = 140 / (140 + zz);
  160. *dst++ = byte(128 + xx * q);
  161. *dst++ = byte(128 + yy * q);
  162. }
  163. }
  164. void draw(struct ship *s, float distance)
  165. {
  166. project(s, distance);
  167. flash_uint8_t *pe = s->edges;
  168. flash_uint8_t *pe_e = pe + (s->nedges * 2);
  169. while (pe < pe_e) {
  170. byte *v0 = &projected[pgm_read_byte_near(pe++) << 1];
  171. byte *v1 = &projected[pgm_read_byte_near(pe++) << 1];
  172. Plotter.line(v0[0], v0[1], v1[0], v1[1]);
  173. }
  174. }
  175. void setup()
  176. {
  177. GD.begin();
  178. GD.ascii();
  179. GD.putstr(0, 0, "Accelerated wireframe");
  180. Plotter.begin();
  181. Serial.begin(1000000); // JCB
  182. }
  183. static byte sn; // Ship number, 0-NSHIPS
  184. static float phi; // Current rotation angle
  185. // Draw one frame of ship
  186. void cycle(float distance)
  187. {
  188. rotation(phi);
  189. phi += 0.02;
  190. draw(&eliteships[sn], distance);
  191. // GD.waitvblank(); // uncomment this to sync to 72Hz frame rate
  192. Plotter.show();
  193. static byte every;
  194. if (++every == 4) {
  195. static long tprev;
  196. long t = micros();
  197. every = 0;
  198. char msg[30];
  199. int fps10 = int(4 * 10000000UL / (t - tprev));
  200. sprintf(msg, "%3d.%d fps ", fps10 / 10, fps10 % 10);
  201. GD.putstr(41, 0, msg);
  202. //screenshot(); // JCB
  203. tprev = t;
  204. tprev = micros(); // JCB
  205. }
  206. }
  207. void loop()
  208. {
  209. const char *name = eliteships[sn].name;
  210. GD.putstr(0, 36, " ");
  211. GD.putstr(25 - strlen(name) / 2, 36, name);
  212. int d;
  213. for (d = 0; d < 100; d++)
  214. cycle(1000 - 10 * d);
  215. for (d = 0; d < 72*6; d++)
  216. cycle(0.0);
  217. for (d = 0; d < 100; d++)
  218. cycle(10 * d);
  219. sn = (sn + 1) % NSHIPS;
  220. }