cube2.ino 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. #include <EEPROM.h>
  2. #include <SPI.h>
  3. #include <GD2.h>
  4. #undef REPORT
  5. #define REPORT(VAR) (Serial.print(#VAR "="), Serial.println(VAR, DEC))
  6. #define FACE_BACK 0
  7. #define FACE_FRONT 1
  8. #define P 125
  9. #define N -P
  10. static const PROGMEM int8_t CUBE_vertices[] = {
  11. P,P,P,
  12. N,P,P,
  13. P,N,P,
  14. N,N,P,
  15. P,P,N,
  16. N,P,N,
  17. P,N,N,
  18. N,N,N,
  19. };
  20. // each line is a face: count, normal, 4 vertices
  21. static const PROGMEM int8_t CUBE_faces[] = {
  22. 4, 0,0,127, 0, 1, 3, 2,
  23. 4, 0,0,-127, 6, 7, 5, 4,
  24. 4, 0,127,0, 4, 5, 1, 0,
  25. 4, 0,-127,0, 2, 3, 7, 6,
  26. 4, 127,0,0, 0, 2, 6, 4,
  27. 4, -127,0,0, 3, 1, 5, 7,
  28. -1
  29. };
  30. ////////////////////////////////////////////////////////////////////////////////
  31. // 3D Projection
  32. ////////////////////////////////////////////////////////////////////////////////
  33. static float model_mat[9] = {
  34. 1.0, 0.0, 0.0,
  35. 0.0, 1.0, 0.0,
  36. 0.0, 0.0, 1.0 };
  37. static float normal_mat[9] = {
  38. 1.0, 0.0, 0.0,
  39. 0.0, 1.0, 0.0,
  40. 0.0, 0.0, 1.0 };
  41. #define M(nm,i,j) ((nm)[3 * (i) + (j)])
  42. // 3x3 matrix multiplication: c = a * b
  43. void mult_matrices(float *a, float *b, float *c)
  44. {
  45. int i, j, k;
  46. float result[9];
  47. for(i = 0; i < 3; i++) {
  48. for(j = 0; j < 3; j++) {
  49. M(result,i,j) = 0.0f;
  50. for(k = 0; k < 3; k++) {
  51. M(result,i,j) += M(a,i,k) * M(b,k,j);
  52. }
  53. }
  54. }
  55. memcpy(c, result, sizeof(result));
  56. }
  57. // Based on glRotate()
  58. // Returns 3x3 rotation matrix in 'm'
  59. // and its invese in 'mi'
  60. static void rotate(float *m, float *mi, float angle, float *axis)
  61. {
  62. float x = axis[0];
  63. float y = axis[1];
  64. float z = axis[2];
  65. float s = sin(angle);
  66. float c = cos(angle);
  67. float xx = x*x*(1-c);
  68. float xy = x*y*(1-c);
  69. float xz = x*z*(1-c);
  70. float yy = y*y*(1-c);
  71. float yz = y*z*(1-c);
  72. float zz = z*z*(1-c);
  73. float xs = x * s;
  74. float ys = y * s;
  75. float zs = z * s;
  76. m[0] = xx + c;
  77. m[1] = xy - zs;
  78. m[2] = xz + ys;
  79. m[3] = xy + zs;
  80. m[4] = yy + c;
  81. m[5] = yz - xs;
  82. m[6] = xz - ys;
  83. m[7] = yz + xs;
  84. m[8] = zz + c;
  85. mi[0] = m[0];
  86. mi[1] = xy + zs;
  87. mi[2] = xz - ys;
  88. mi[3] = xy - zs;
  89. mi[4] = m[4];
  90. mi[5] = yz + xs;
  91. mi[6] = xz + ys;
  92. mi[7] = yz - xs;
  93. mi[8] = m[8];
  94. }
  95. static void rotation(float angle, float *axis)
  96. {
  97. float mat[9], mati[9];
  98. rotate(mat, mati, angle, axis);
  99. mult_matrices(model_mat, mat, model_mat);
  100. mult_matrices(mati, normal_mat, normal_mat);
  101. }
  102. #define N_VERTICES (sizeof(CUBE_vertices) / 3)
  103. typedef struct {
  104. int x, y;
  105. } point2;
  106. static point2 projected[N_VERTICES];
  107. void project()
  108. {
  109. byte vx;
  110. const PROGMEM int8_t *pm = CUBE_vertices;
  111. const PROGMEM int8_t *pm_e = pm + sizeof(CUBE_vertices);
  112. point2 *dst = projected;
  113. int16_t x, y, z;
  114. int scale = 64 * GD.h / 280;
  115. while (pm < pm_e) {
  116. x = (scale * (int8_t)pgm_read_byte_near(pm++)) >> 6;
  117. y = (scale * (int8_t)pgm_read_byte_near(pm++)) >> 6;
  118. z = (scale * (int8_t)pgm_read_byte_near(pm++)) >> 6;
  119. float xx = x * model_mat[0] + y * model_mat[3] + z * model_mat[6];
  120. float yy = x * model_mat[1] + y * model_mat[4] + z * model_mat[7];
  121. dst->x = 16 * (GD.w / 2 + xx);
  122. dst->y = 16 * (GD.h / 2 + yy);
  123. dst++;
  124. }
  125. }
  126. static void transform_normal(int8_t &nx, int8_t &ny, int8_t &nz)
  127. {
  128. int8_t xx = nx * normal_mat[0] + ny * normal_mat[1] + nz * normal_mat[2];
  129. int8_t yy = nx * normal_mat[3] + ny * normal_mat[4] + nz * normal_mat[5];
  130. int8_t zz = nx * normal_mat[6] + ny * normal_mat[7] + nz * normal_mat[8];
  131. nx = xx, ny = yy, nz = zz;
  132. }
  133. static void quad(int x1, int y1,
  134. int x2, int y2,
  135. int x3, int y3,
  136. int bx1, int by1,
  137. int bx3, int by3)
  138. {
  139. // Compute the fourth vertex of the parallelogram, (x4,y4)
  140. int x4 = x3 + (x1 - x2);
  141. int y4 = y3 + (y1 - y2);
  142. // Apply Scissor to the extents of the quad
  143. int minx = max(0, min(min(x1, x2), min(x3, x4)));
  144. int maxx = min(GD.w, max(max(x1, x2), max(x3, x4)));
  145. int miny = max(0, min(min(y1, y2), min(y3, y4)));
  146. int maxy = min(GD.h, max(max(y1, y2), max(y3, y4)));
  147. GD.ScissorXY(minx, miny);
  148. GD.ScissorSize(maxx - minx, maxy - miny);
  149. // GD.ClearColorRGB(0, 255, 0); GD.Clear();
  150. // Set the new bitmap transform
  151. GD.cmd32(0xffffff21UL); // bitmap transform
  152. GD.cmd32(x1 - minx); GD.cmd32(y1 - miny);
  153. GD.cmd32(x2 - minx); GD.cmd32(y2 - miny);
  154. GD.cmd32(x3 - minx); GD.cmd32(y3 - miny);
  155. GD.cmd32(bx1); GD.cmd32(by1);
  156. GD.cmd32(bx1); GD.cmd32(by3);
  157. GD.cmd32(bx3); GD.cmd32(by3);
  158. GD.cmd32(0);
  159. // Draw the quad
  160. GD.Vertex2f(PIXELS(minx), PIXELS(miny));
  161. }
  162. void draw_faces(int dir)
  163. {
  164. int R = 15;
  165. const PROGMEM int8_t *p = CUBE_faces;
  166. byte n;
  167. GD.BlendFunc(ONE, ONE_MINUS_SRC_ALPHA);
  168. GD.Begin(BITMAPS);
  169. byte i = 0;
  170. while ((n = pgm_read_byte_near(p++)) != 0xff) {
  171. int8_t nx = pgm_read_byte_near(p++);
  172. int8_t ny = pgm_read_byte_near(p++);
  173. int8_t nz = pgm_read_byte_near(p++);
  174. byte v1 = pgm_read_byte_near(p);
  175. byte v2 = pgm_read_byte_near(p + 1);
  176. byte v3 = pgm_read_byte_near(p + 2);
  177. p += n;
  178. long x1 = projected[v1].x;
  179. long y1 = projected[v1].y;
  180. long x2 = projected[v2].x;
  181. long y2 = projected[v2].y;
  182. long x3 = projected[v3].x;
  183. long y3 = projected[v3].y;
  184. long area = (x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1);
  185. byte face = (area < 0);
  186. if (face == dir) {
  187. uint16_t r = 80, g = 40, b = 0; // Ambient
  188. if (face) {
  189. transform_normal(nx, ny, nz);
  190. int d = max(0, -nz); // diffuse light from +ve Z
  191. r += 2 * d;
  192. g += 2 * d;
  193. b += 2 * d;
  194. }
  195. r = constrain(r, 192, 255);
  196. GD.ColorRGB(min(255, r), min(255, g), min(255, b));
  197. GD.BitmapHandle(face);
  198. GD.Cell(i);
  199. i = (i + 1) & 3;
  200. x1 >>= 4;
  201. y1 >>= 4;
  202. x2 >>= 4;
  203. y2 >>= 4;
  204. x3 >>= 4;
  205. y3 >>= 4;
  206. quad(x1, y1, x2, y2, x3, y3,
  207. 80 - 90, 64 - 90,
  208. 80 + 90, 64 + 90);
  209. }
  210. }
  211. }
  212. /*****************************************************************/
  213. /* simple trackball-like motion control */
  214. /* Based on projtex.c - by David Yu and David Blythe, SGI */
  215. float angle, axis[3] = {0,1,0};
  216. float lastPos[3];
  217. void
  218. ptov(int x, int y, int width, int height, float v[3])
  219. {
  220. float d, a;
  221. /* project x,y onto a hemi-sphere centered within width, height */
  222. v[0] = (2.0 * x - width) / width;
  223. v[1] = (2.0 * y - height) / height;
  224. d = sqrt(v[0] * v[0] + v[1] * v[1]);
  225. v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
  226. a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  227. v[0] *= a;
  228. v[1] *= a;
  229. v[2] *= a;
  230. }
  231. void
  232. startMotion(int x, int y)
  233. {
  234. angle = 0.0;
  235. ptov(x, y, GD.w, GD.h, lastPos);
  236. }
  237. void
  238. trackMotion(int x, int y)
  239. {
  240. float curPos[3], dx, dy, dz;
  241. ptov(x, y, GD.w, GD.h, curPos);
  242. dx = curPos[0] - lastPos[0];
  243. dy = curPos[1] - lastPos[1];
  244. dz = curPos[2] - lastPos[2];
  245. angle = (M_PI / 2) * sqrt(dx * dx + dy * dy + dz * dz);
  246. axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
  247. axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
  248. axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
  249. float mag = 1 / sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
  250. axis[0] *= mag;
  251. axis[1] *= mag;
  252. axis[2] *= mag;
  253. lastPos[0] = curPos[0];
  254. lastPos[1] = curPos[1];
  255. lastPos[2] = curPos[2];
  256. }
  257. /*****************************************************************/
  258. uint32_t f0;
  259. int qq;
  260. class MoviePlayer2
  261. {
  262. uint16_t wp;
  263. Reader r;
  264. void loadsector() {
  265. byte buf[512];
  266. GD.__end();
  267. r.readsector(buf);
  268. GD.resume();
  269. GD.wr_n(0x0f0000UL + wp, buf, 512);
  270. wp += 512;
  271. }
  272. public:
  273. int begin(const char *filename) {
  274. GD.__end();
  275. if (!r.openfile(filename)) {
  276. Serial.println("Open failed");
  277. return 0;
  278. }
  279. GD.resume();
  280. uint32_t t0 = millis();
  281. wp = 0;
  282. while (wp < 0xfe00U)
  283. loadsector();
  284. uint32_t took = (millis() - t0);
  285. Serial.println(took);
  286. Serial.print(1000L * wp / took);
  287. Serial.println(" bytes/s");
  288. GD.cmd_mediafifo(0x0f0000UL, 0x10000UL);
  289. GD.cmd_regwrite(REG_MEDIAFIFO_WRITE, wp);
  290. GD.finish();
  291. if (0) {
  292. GD.cmd_playvideo(OPT_MEDIAFIFO);
  293. } else {
  294. GD.cmd_videostart();
  295. }
  296. f0 = millis();
  297. return 1;
  298. }
  299. int service() {
  300. if (r.eof()) {
  301. return 0;
  302. } else {
  303. byte buf[512];
  304. uint16_t fullness = wp - GD.rd16(REG_MEDIAFIFO_READ);
  305. qq = 0;
  306. while (fullness < 0xfe00U) {
  307. loadsector();
  308. fullness += 512;
  309. qq += 512;
  310. }
  311. GD.wr16(REG_MEDIAFIFO_WRITE, wp);
  312. return 1;
  313. }
  314. }
  315. };
  316. MoviePlayer2 mp;
  317. /*****************************************************************/
  318. #define BG 25
  319. Bitmap background;
  320. void setup()
  321. {
  322. Serial.begin(1000000);
  323. GD.begin();
  324. // background.fromfile("tile1920.jpg");
  325. GD.Clear();
  326. GD.cmd_text(GD.w / 2, GD.h / 2, 31, OPT_CENTER, "Loading video");
  327. GD.BitmapHandle(0);
  328. GD.cmd_setbitmap(0, RGB565, 160, 128);
  329. GD.BitmapHandle(1);
  330. GD.cmd_setbitmap(0, RGB565, 160, 128);
  331. GD.swap();
  332. mp.begin("70s_tv09.avi");
  333. GD.Clear();
  334. GD.swap();
  335. GD.BitmapHandle(FACE_FRONT);
  336. GD.BitmapSize(BILINEAR, BORDER, BORDER, GD.w, GD.h);
  337. GD.BitmapSource(GD.loadptr);
  338. GD.BitmapHandle(FACE_BACK);
  339. GD.BitmapSize(NEAREST, BORDER, BORDER, GD.w, GD.h);
  340. GD.BitmapSource(GD.loadptr);
  341. startMotion(240, 136);
  342. trackMotion(247, 138);
  343. }
  344. byte prev_touching;
  345. void loop()
  346. {
  347. unsigned long t0 = micros();
  348. mp.service();
  349. unsigned long took = micros() - t0;
  350. GD.get_inputs();
  351. GD.cmd_videoframe(GD.loadptr + 4, GD.loadptr);
  352. GD.Clear();
  353. GD.ColorRGB(48, 48, 90);
  354. // background.wallpaper();
  355. GD.ColorRGB(255, 255, 255);
  356. if (!prev_touching && GD.inputs.touching)
  357. startMotion(GD.inputs.x, GD.inputs.y);
  358. else if (GD.inputs.touching)
  359. trackMotion(GD.inputs.x, GD.inputs.y);
  360. prev_touching = GD.inputs.touching;
  361. if (angle != 0.0f)
  362. rotation(angle, axis);
  363. project();
  364. draw_faces(FACE_BACK);
  365. draw_faces(FACE_FRONT);
  366. GD.swap();
  367. }