viewer.ino 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include <EEPROM.h>
  2. #include <SPI.h>
  3. #include <GD2.h>
  4. class scroller {
  5. public:
  6. signed short dragprev;
  7. int vel; // velocity
  8. long base; // screen x coordinate, in 1/16ths pixel
  9. long limit;
  10. void init(uint32_t lim) {
  11. dragprev = -32768;
  12. vel = 0; // velocity
  13. base = 0; // screen x coordinate, in 1/16ths pixel
  14. limit = lim;
  15. }
  16. void run(bool touching, int16_t sx) {
  17. if (touching & (dragprev != -32768)) {
  18. vel = (dragprev - sx) << 4;
  19. } else {
  20. int change = max(1, abs(vel) >> 5);
  21. if (vel < 0)
  22. vel += change;
  23. if (vel > 0)
  24. vel -= change;
  25. }
  26. dragprev = touching ? sx : -32768;
  27. base += vel;
  28. base = max(0, min(base, limit));
  29. }
  30. uint16_t getval() {
  31. return base >> 4;
  32. }
  33. };
  34. void setup()
  35. {
  36. Serial.begin(1000000); // JCB
  37. GD.begin();
  38. }
  39. #define PROGRESS_Y 136
  40. static void progress(long a, long b)
  41. {
  42. GD.wr32(REG_MACRO_0, VERTEX2II(40 + 399 * a / b, PROGRESS_Y, 0, 0));
  43. }
  44. static void draw_progress()
  45. {
  46. GD.Begin(LINES);
  47. GD.ColorRGB(0xc0c0c0);
  48. GD.LineWidth(16 * 5);
  49. GD.Vertex2ii(40, PROGRESS_Y);
  50. GD.Vertex2ii(440, PROGRESS_Y);
  51. GD.ColorRGB(0x000000);
  52. GD.LineWidth(16 * 3);
  53. GD.Vertex2ii(40, PROGRESS_Y);
  54. GD.Vertex2ii(440, PROGRESS_Y);
  55. GD.ColorRGB(0xffffff);
  56. GD.LineWidth(16 * 2);
  57. GD.Vertex2ii(40, PROGRESS_Y);
  58. GD.Macro(0);
  59. GD.swap();
  60. }
  61. static void paint_alpha()
  62. {
  63. GD.ColorMask(0, 0, 0, 1);
  64. GD.Clear();
  65. }
  66. static void use_alpha()
  67. {
  68. GD.ColorMask(1, 1, 1, 1);
  69. GD.BlendFunc(DST_ALPHA, ONE_MINUS_DST_ALPHA);
  70. }
  71. static char *getdir(char directory[60][8], int i)
  72. {
  73. static char nm[8 + 1 + 3 + 1];
  74. nm[8] = 0;
  75. strncpy(nm, directory[i], 8);
  76. strcat(nm, ".jpg");
  77. return nm;
  78. }
  79. static void showdir0(char directory[60][8], int num_jpgs, int yb, int sel)
  80. {
  81. GD.Tag(0);
  82. GD.SaveContext();
  83. GD.ScissorSize(480, 136);
  84. GD.cmd_gradient(0, 0, 0x3030c0, 0, 136, 0x000000);
  85. GD.ScissorXY(0, 136);
  86. GD.cmd_gradient(0, 136, 0x080800, 0, 272, 0x908880);
  87. GD.RestoreContext();
  88. GD.LineWidth(48);
  89. GD.Begin(RECTS);
  90. GD.ColorRGB(0xffffff);
  91. for (int j = 0; j < num_jpgs; j++) {
  92. int y = 40 * j - yb;
  93. if ((-50 < y) && (y < 272)) {
  94. GD.ColorA((sel == j) ? 0xff : 0xa0);
  95. GD.Vertex2f(16 * (240 - 100), 16 * (y + 6));
  96. GD.Vertex2f(16 * (240 + 100), 16 * (y + 40 - 6));
  97. }
  98. }
  99. }
  100. static void showdir1(char directory[60][8], int num_jpgs, int yb, int sel)
  101. {
  102. GD.ColorA(0xff);
  103. GD.ColorRGB(0x000000);
  104. for (int j = 0; j < num_jpgs; j++) {
  105. int y = 40 * j - yb;
  106. if ((-50 < y) && (y < 272)) {
  107. GD.Tag(128 + j);
  108. GD.cmd_text(240, y + 18, 28, OPT_CENTER, getdir(directory, j));
  109. }
  110. }
  111. }
  112. #ifdef DUMPDEV // JCB{
  113. extern FILE *stimfile;
  114. #endif // }JCB
  115. void loop()
  116. {
  117. char directory[60][8];
  118. int num_jpgs = 0;
  119. int picked;
  120. scroller yscroll;
  121. {
  122. #ifdef DUMPDEV // JCB{
  123. char fn[9];
  124. for (int i = 1; i < 40; i++) {
  125. sprintf(fn, "kitten%02d", i);
  126. memcpy(directory[num_jpgs++], fn , 8);
  127. }
  128. memcpy(directory[num_jpgs++], "selfie" , 8);
  129. #else // }JCB
  130. int j = 0;
  131. dirent de;
  132. GD.__end();
  133. do {
  134. GD.SD.rdn((byte*)&de, GD.SD.o_root + j * 32, sizeof(de));
  135. if ((0x20 < de.name[0]) && (de.name[0] < 0x80)) {
  136. if (memcmp(de.ext, "JPG", 3) == 0) {
  137. if (num_jpgs < 60) {
  138. char *pd = directory[num_jpgs++];
  139. byte i;
  140. for (i = 0; i < 8 && de.name[i] != ' '; i++)
  141. *pd++ = tolower(de.name[i]);
  142. if (i != 8)
  143. *pd = 0;
  144. }
  145. }
  146. }
  147. j++;
  148. } while (de.name[0]);
  149. GD.resume();
  150. #endif // JCB
  151. yscroll.init((40L * (num_jpgs - 4)) << 4);
  152. do {
  153. GD.get_inputs();
  154. byte touching = (GD.inputs.x != -32768) && (GD.inputs.tag < 128);
  155. yscroll.run(touching, GD.inputs.y);
  156. showdir0(directory, num_jpgs, yscroll.base >> 4, -1);
  157. showdir1(directory, num_jpgs, yscroll.base >> 4, -1);
  158. GD.swap();
  159. } while (GD.inputs.tag < 128);
  160. picked = GD.inputs.tag - 128;
  161. }
  162. #ifndef DUMPDEV // JCB
  163. GD.Clear();
  164. draw_progress();
  165. #else // JCB{
  166. for (int i = 0; i < 30; i++) {
  167. showdir0(directory, num_jpgs, yscroll.base >> 4, picked);
  168. showdir1(directory, num_jpgs, yscroll.base >> 4, picked);
  169. GD.swap();
  170. }
  171. #endif // }JCB
  172. GD.cmd_loadimage(0, 0);
  173. int ok = GD.load(getdir(directory, picked), progress);
  174. uint32_t m_ptr, m_w, m_h;
  175. GD.cmd_getprops(m_ptr, m_w, m_h);
  176. GD.finish();
  177. #ifndef DUMPDEV // JCB
  178. uint16_t w = GD.rd16(m_w);
  179. uint16_t h = GD.rd16(m_h);
  180. #else // JCB{
  181. uint16_t w = 335;
  182. uint16_t h = 272;
  183. #endif // }JCB
  184. byte prev_touching = 0;
  185. int cx, cy;
  186. float smooth_r;
  187. GD.BitmapSize(BILINEAR, BORDER, BORDER, w, h);
  188. float zoom = 0.3;
  189. int fadeout = 0;
  190. #ifdef DUMPDEV // JCB{
  191. while (!feof(stimfile)) {
  192. #else // }JCB
  193. while (1) {
  194. #endif // JCB
  195. GD.get_inputs();
  196. byte touching = GD.inputs.x != -32768;
  197. showdir0(directory, num_jpgs, yscroll.base >> 4, picked);
  198. showdir1(directory, num_jpgs, yscroll.base >> 4, picked);
  199. GD.ColorRGB(0xffffff);
  200. int zw = zoom * w / 2;
  201. int zh = zoom * h / 2;
  202. GD.Begin(BITMAPS);
  203. GD.cmd_scale(F16(zoom), F16(zoom));
  204. GD.cmd_setmatrix();
  205. GD.Vertex2ii(240 - zw, 136 - zh, 0, 0);
  206. zoom = min(1.0, zoom * 1.2);
  207. if (touching) {
  208. if (!prev_touching) {
  209. cx = GD.inputs.x;
  210. cy = GD.inputs.y;
  211. smooth_r = 0;
  212. } else {
  213. int dx = cx - GD.inputs.x;
  214. int dy = cy - GD.inputs.y;
  215. float r = sqrt(dx * dx + dy * dy);
  216. smooth_r = .75 * smooth_r + 0.25 * r;
  217. }
  218. fadeout = 15;
  219. }
  220. if (fadeout) {
  221. fadeout--;
  222. smooth_r += 1;
  223. }
  224. if (touching || fadeout) {
  225. int r0 = int(15 * smooth_r);
  226. int r1 = int(16 * smooth_r);
  227. float fade = min(fadeout / 15., smooth_r / 40);
  228. GD.SaveContext();
  229. GD.ClearColorA(128 * fade);
  230. paint_alpha();
  231. GD.Begin(POINTS);
  232. GD.BlendFunc(ZERO, ONE_MINUS_SRC_ALPHA);
  233. GD.PointSize(r1);
  234. GD.Vertex2ii(cx, cy);
  235. use_alpha();
  236. GD.ColorRGB(0x000000);
  237. GD.Begin(RECTS);
  238. GD.Vertex2ii(0, 0);
  239. GD.Vertex2ii(480, 272);
  240. GD.RestoreContext();
  241. paint_alpha();
  242. GD.Begin(POINTS);
  243. GD.ColorA(255 * fadeout / 15);
  244. GD.BlendFunc(ONE, ONE_MINUS_SRC_ALPHA);
  245. GD.PointSize(r1);
  246. GD.Vertex2ii(cx, cy);
  247. GD.ColorA(255);
  248. GD.BlendFunc(ZERO, ONE_MINUS_SRC_ALPHA);
  249. GD.PointSize(r0);
  250. GD.Vertex2ii(cx, cy);
  251. use_alpha();
  252. GD.PointSize(r1);
  253. GD.Vertex2ii(cx, cy);
  254. }
  255. GD.swap();
  256. prev_touching = touching;
  257. }
  258. }