dna.ino 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include <stdlib.h>
  2. #include <SPI.h>
  3. #include <GD.h>
  4. static uint16_t SWAP_RB(uint16_t color) // Swap red and blue channel
  5. {
  6. byte r = (color >> 10) & 31;
  7. byte g = (color >> 5) & 31;
  8. byte b = color & 31;
  9. return (color & 0x8000) | (b << 10) | (g << 5) | (r);
  10. }
  11. static uint16_t SWAP_RG(uint16_t color) // Swap red and blue channel
  12. {
  13. byte r = (color >> 10) & 31;
  14. byte g = (color >> 5) & 31;
  15. byte b = color & 31;
  16. return (color & 0x8000) | (g << 10) | (r << 5) | (b);
  17. }
  18. #include "dna.h"
  19. ////////////////////////////////////////////////////////////////////////////////
  20. // 3D Projection
  21. ////////////////////////////////////////////////////////////////////////////////
  22. static float mats[2][9];
  23. static float mat[9];
  24. // Taken from glRotate()
  25. static void rotation(float phi)
  26. {
  27. float x = 0.57735026918962573;
  28. float y = 0.57735026918962573;
  29. float z = 0.57735026918962573;
  30. float s = sin(phi);
  31. float c = cos(phi);
  32. mat[0] = x*x*(1-c)+c;
  33. mat[1] = x*y*(1-c)-z*s;
  34. mat[2] = x*z*(1-c)+y*s;
  35. mat[3] = y*x*(1-c)+z*s;
  36. mat[4] = y*y*(1-c)+c;
  37. mat[5] = y*z*(1-c)-x*s;
  38. mat[6] = x*z*(1-c)-y*s;
  39. mat[7] = y*z*(1-c)+x*s;
  40. mat[8] = z*z*(1-c)+c;
  41. }
  42. #ifdef MAPLE_IDE
  43. #define NVERTICES 250
  44. #else
  45. #define NVERTICES 220 // Arduino does not have enough RAM for all 250
  46. #endif
  47. struct screenpt {
  48. short x, y, z;
  49. };
  50. static struct screenpt projected[NVERTICES];
  51. void project(float distance)
  52. {
  53. byte vx;
  54. flash_int8_t *pm = cloud;
  55. flash_int8_t *pm_e = cloud + (NVERTICES*3);
  56. struct screenpt *dst = projected;
  57. signed char x, y, z;
  58. while (pm < pm_e) {
  59. x = pgm_read_byte_near(pm++);
  60. y = pgm_read_byte_near(pm++);
  61. z = pgm_read_byte_near(pm++);
  62. float xx = x * mat[0] + y * mat[3] + z * mat[6];
  63. float yy = x * mat[1] + y * mat[4] + z * mat[7];
  64. float zz = x * mat[2] + y * mat[5] + z * mat[8] + distance;
  65. int scale = 200;
  66. float q = scale / (250 + zz);
  67. dst->x = (511 & int(200 + xx * q)) | (((x^y^z) & 3) << 14);
  68. dst->y = int(150 + yy * q);
  69. dst->z = int(zz * 100);
  70. dst++;
  71. }
  72. }
  73. // point depth comparison, for depth sort
  74. int ptcmp(const void *va, const void *vb)
  75. {
  76. struct screenpt *a = (struct screenpt *)va;
  77. struct screenpt *b = (struct screenpt *)vb;
  78. if (a->z < b->z)
  79. return 1;
  80. else if (a->z > b->z)
  81. return -1;
  82. else
  83. return 0;
  84. }
  85. // load a sprite at (x,y). z is distance 0-63, color is 0-3
  86. static void render_sphere(int x, int y, byte z, byte color)
  87. {
  88. static byte pals[4][2] = {
  89. { 4,6 },
  90. { 5,7 },
  91. { 0,1 },
  92. { 2,3 }};
  93. int ox = x - 8;
  94. int oy = y - 8;
  95. byte palette = pals[color][z & 1];
  96. byte image = (z >> 1);
  97. SPI.transfer(lowByte(ox));
  98. SPI.transfer((palette << 4) | (highByte(ox) & 1));
  99. SPI.transfer(lowByte(oy));
  100. SPI.transfer((image << 1) | (highByte(oy) & 1));
  101. }
  102. void draw(float distance)
  103. {
  104. project(distance);
  105. qsort(projected, NVERTICES, sizeof(struct screenpt), ptcmp);
  106. static byte flip;
  107. GD.__wstartspr(flip ? 256 : 0);
  108. for (int i = 0; i < NVERTICES; i++) {
  109. byte color = (projected[i].x >> 14) & 3;
  110. short x = projected[i].x & 511;
  111. short y = projected[i].y;
  112. int z = max(0, min(63, int(32 + projected[i].z / 500)));
  113. render_sphere(x, y, z, color);
  114. }
  115. GD.__end();
  116. GD.wr(SPR_PAGE, flip);
  117. // if (flip == 0) rawdump(RAM_SPR, 1024); // JCB
  118. flip = !flip;
  119. }
  120. static float phi; // Current rotation angle
  121. // Draw one frame of ship
  122. void cycle(float distance)
  123. {
  124. rotation(phi);
  125. phi += 0.02;
  126. draw(distance);
  127. // if (0) // JCB
  128. { // report frame rate in top-right
  129. static byte every;
  130. if (++every == 4) {
  131. static long tprev;
  132. long t = micros();
  133. every = 0;
  134. char msg[30];
  135. int fps10 = int(4 * 10000000UL / (t - tprev));
  136. sprintf(msg, "%3d.%d fps ", fps10 / 10, fps10 % 10);
  137. GD.putstr(41, 0, msg);
  138. tprev = t;
  139. }
  140. }
  141. }
  142. static uint16_t rdpal(byte i)
  143. {
  144. return pgm_read_word_near(sphere_pal + (i << 1));
  145. }
  146. void setup()
  147. {
  148. GD.begin();
  149. GD.ascii();
  150. Serial.begin(1000000); // JCB
  151. for (byte y = 0; y < 38; y++) {
  152. flash_uint8_t *src = ramp_pic + y * 4;
  153. for (byte x = 0; x < 50; x++)
  154. GD.wr(RAM_PIC + y * 64 + x, pgm_read_byte(src + random(4)));
  155. }
  156. GD.copy(RAM_CHR + 128 * 16, ramp_chr, sizeof(ramp_chr));
  157. GD.copy(RAM_PAL + 128 * 8, ramp_pal, sizeof(ramp_pal));
  158. GD.copy(PALETTE16A, sphere_pal, sizeof(sphere_pal));
  159. for (byte i = 0; i < 16; i++) {
  160. GD.wr16(PALETTE16B + 2 * i, SWAP_RB(rdpal(i)));
  161. }
  162. for (int i = 0; i < 256; i++) {
  163. // palette 0 decodes low nibble, hence (i & 15)
  164. GD.wr16(RAM_SPRPAL + (i << 1), SWAP_RG(rdpal(i & 15)));
  165. // palette 1 decodes nigh nibble, hence (i >> 4)
  166. GD.wr16(RAM_SPRPAL + 512 + (i << 1), SWAP_RG(rdpal(i >> 4)));
  167. // palette 0 decodes low nibble, hence (i & 15)
  168. GD.wr16(RAM_SPRPAL + 1024 + (i << 1), SWAP_RB(SWAP_RG(rdpal(i & 15))));
  169. // palette 1 decodes nigh nibble, hence (i >> 4)
  170. GD.wr16(RAM_SPRPAL + 1024 + 512 + (i << 1), SWAP_RB(SWAP_RG(rdpal(i >> 4))));
  171. }
  172. GD.copy(RAM_SPRIMG, sphere_img, sizeof(sphere_img));
  173. // rawdump(0, 32768); // JCB
  174. #ifdef MAPLE_IDE
  175. GD.putstr(0, 0, "DNA demo: Gameduino with Maple");
  176. #else
  177. GD.putstr(0, 0, "DNA demo: Gameduino with Arduino");
  178. #endif
  179. }
  180. void loop()
  181. {
  182. cycle(0.0);
  183. }