welcome.ino 10 KB

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