fbutil.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
  1. /*
  2. * Copyright (c) 2019 Clementine Computing LLC.
  3. *
  4. * This file is part of PopuFare.
  5. *
  6. * PopuFare is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * PopuFare is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include <sys/termios.h>
  21. #include <sys/ioctl.h>
  22. #include <sys/mman.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <linux/fb.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <poll.h>
  29. #include <unistd.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <regex.h>
  33. #include <fcntl.h>
  34. #include "../common/common_defs.h"
  35. #include "fbutil.h"
  36. #include "fbfonts.h"
  37. extern fbfont smallfont;
  38. extern fbfont medfont;
  39. extern fbfont bigfont;
  40. // This include file contains the palette tables for storing the old palette to be later restored, as well as
  41. //the palette table we use for our application. It also has a byzantine and insane table where I have factored out
  42. //all of the possible permutations of painting color X over color Y with or without the blend bit set in color X, so
  43. //you can use the LOOKUP_BLEND(x, y) macro and it will return the resulting color.
  44. #include "color_tables.h"
  45. //-------------------------------
  46. named_color color_names[] =
  47. {
  48. {"white", FBCOLOR_WHITE},
  49. {"light_gray", FBCOLOR_GRAY},
  50. {"dark_gray", FBCOLOR_DKGRAY},
  51. {"black", FBCOLOR_BLACK},
  52. {"trans_white", FBCOLOR_WHITE | FBCOLOR_TRANSLUCENT},
  53. {"trans_light_gray", FBCOLOR_GRAY | FBCOLOR_TRANSLUCENT},
  54. {"trans_dark_gray", FBCOLOR_DKGRAY | FBCOLOR_TRANSLUCENT},
  55. {"trans_black", FBCOLOR_BLACK | FBCOLOR_TRANSLUCENT},
  56. {"dark_red", FBCOLOR_DKRED},
  57. {"red", FBCOLOR_RED},
  58. {"light_red", FBCOLOR_LTRED},
  59. {"trans_dark_red", FBCOLOR_DKRED | FBCOLOR_TRANSLUCENT},
  60. {"trans_red", FBCOLOR_RED | FBCOLOR_TRANSLUCENT},
  61. {"trans_light_red", FBCOLOR_LTRED | FBCOLOR_TRANSLUCENT},
  62. {"dark_green", FBCOLOR_DKGREEN},
  63. {"green", FBCOLOR_GREEN},
  64. {"light_green", FBCOLOR_LTGREEN},
  65. {"trans_dark_green", FBCOLOR_DKGREEN | FBCOLOR_TRANSLUCENT},
  66. {"trans_green", FBCOLOR_GREEN | FBCOLOR_TRANSLUCENT},
  67. {"trans_light_green", FBCOLOR_LTGREEN | FBCOLOR_TRANSLUCENT},
  68. {"dark_blue", FBCOLOR_DKBLUE},
  69. {"blue", FBCOLOR_BLUE},
  70. {"light_blue", FBCOLOR_LTBLUE},
  71. {"trans_dark_blue", FBCOLOR_DKBLUE | FBCOLOR_TRANSLUCENT},
  72. {"trans_blue", FBCOLOR_BLUE | FBCOLOR_TRANSLUCENT},
  73. {"trans_light_blue", FBCOLOR_LTBLUE | FBCOLOR_TRANSLUCENT},
  74. {"dark_yellow", FBCOLOR_DKYELLOW},
  75. {"yellow", FBCOLOR_YELLOW},
  76. {"light_yellow", FBCOLOR_LTYELLOW},
  77. {"trans_dark_yellow", FBCOLOR_DKYELLOW | FBCOLOR_TRANSLUCENT},
  78. {"trans_yellow", FBCOLOR_YELLOW | FBCOLOR_TRANSLUCENT},
  79. {"trans_light_yellow", FBCOLOR_LTYELLOW | FBCOLOR_TRANSLUCENT},
  80. {"dark_cyan", FBCOLOR_DKCYAN},
  81. {"cyan", FBCOLOR_CYAN},
  82. {"light_cyan", FBCOLOR_LTCYAN},
  83. {"trans_dark_cyan", FBCOLOR_DKCYAN | FBCOLOR_TRANSLUCENT},
  84. {"trans_cyan", FBCOLOR_CYAN | FBCOLOR_TRANSLUCENT},
  85. {"trans_light_cyan", FBCOLOR_LTCYAN | FBCOLOR_TRANSLUCENT},
  86. {"dark_magenta", FBCOLOR_DKMAGENTA},
  87. {"magenta", FBCOLOR_MAGENTA},
  88. {"light_magenta", FBCOLOR_LTMAGENTA},
  89. {"trans_dark_magenta", FBCOLOR_DKMAGENTA | FBCOLOR_TRANSLUCENT},
  90. {"trans_magenta", FBCOLOR_MAGENTA | FBCOLOR_TRANSLUCENT},
  91. {"trans_light_magenta", FBCOLOR_LTMAGENTA | FBCOLOR_TRANSLUCENT},
  92. {NULL, 0} //THIS TERMINATOR IS NEEDED SO WE DON'T WALK OFF THE END OF THE LIST!
  93. };
  94. static inline unsigned int consume_hex_digits(char **s, int digits)
  95. {
  96. unsigned int accum = 0;
  97. int i;
  98. char *trav;
  99. if(!s)
  100. return 0;
  101. trav = *s;
  102. if(!trav)
  103. return 0;
  104. for(i = 0; i < digits; i++)
  105. {
  106. if(!*trav)
  107. break;
  108. switch(*trav)
  109. {
  110. case 0:
  111. case 1:
  112. case 2:
  113. case 3:
  114. case 4:
  115. case 5:
  116. case 6:
  117. case 7:
  118. case 8:
  119. case 9:
  120. accum |= (*trav) - '0';
  121. accum <<= 4;
  122. trav++;
  123. break;
  124. case 'A':
  125. case 'B':
  126. case 'C':
  127. case 'D':
  128. case 'E':
  129. case 'F':
  130. accum |= (*trav) - '7';
  131. accum <<= 4;
  132. trav++;
  133. break;
  134. case 'a':
  135. case 'b':
  136. case 'c':
  137. case 'd':
  138. case 'e':
  139. case 'f':
  140. accum |= (*trav) - 'W';
  141. accum <<= 4;
  142. trav++;
  143. break;
  144. default:
  145. *s = trav;
  146. return accum;
  147. break;
  148. }
  149. }
  150. *s = trav;
  151. return accum;
  152. }
  153. pixel string_to_color(char *str)
  154. {
  155. char *trav;
  156. pixel color = FBCOLOR_BLACK;
  157. int i;
  158. int r = 0, g = 0, b = 0, a = 0xFF;
  159. if(str)
  160. {
  161. trav = str;
  162. if(*trav == '#') //If we have a numeric color
  163. {
  164. trav++;
  165. i = 0;
  166. r = consume_hex_digits(&trav, 2); //Get the first hex octet
  167. if(*trav) //if there are more characters, we'll expect at least #rrggbb
  168. {
  169. g = consume_hex_digits(&trav, 2); //covert green
  170. b = consume_hex_digits(&trav, 2); //and blue
  171. if(*trav) //if there are still more characters, it may be #rrggbbaa
  172. {
  173. a = consume_hex_digits(&trav, 2); //convert alpha
  174. }
  175. color = FROM_RGBA(r,g,b,a); //make a framebuffer color from the supplied RGBA values
  176. }
  177. else //otherwise, treat the single octet as a raw framebuffer color
  178. {
  179. color = r; //if we only got one octet, use it as a raw color
  180. }
  181. }
  182. else //if there was no # to indicate a numeric color, let's scan our list of named colors
  183. {
  184. i = 0;
  185. while(1)
  186. {
  187. if(color_names[i].name == NULL) //if we've hit the end of the list
  188. {
  189. break; //give up
  190. }
  191. if(!strcasecmp(color_names[i].name, trav)) //if it matches
  192. {
  193. color = color_names[i].color; //snag the color and we're done
  194. break;
  195. }
  196. else
  197. {
  198. i++; //otherwise, try the next one
  199. }
  200. }
  201. }
  202. }
  203. return color; //report our results back
  204. }
  205. static unsigned int clip_x = 0;
  206. static unsigned int clip_y = 0;
  207. static unsigned int clip_xx = XRES;
  208. static unsigned int clip_yy = YRES;
  209. void reset_clip_rect()
  210. {
  211. clip_x = 0;
  212. clip_y = 0;
  213. clip_xx = XRES;
  214. clip_yy = YRES;
  215. }
  216. #define SWAP(a,b) {tmp = a; a = b; b = tmp;}
  217. void set_clip_rect(unsigned x, unsigned y, unsigned xx, unsigned yy)
  218. {
  219. int tmp;
  220. if(x > xx) SWAP(x, xx);
  221. if(y > yy) SWAP(y, yy);
  222. clip_x = (x <= XRES)?x:XRES;
  223. clip_xx = (xx <= XRES)?xx:XRES;
  224. clip_y = (y <= YRES)?y:YRES;
  225. clip_yy = (yy <= YRES)?yy:YRES;
  226. }
  227. void get_clip_rect(unsigned *x, unsigned *y, unsigned *xx, unsigned *yy)
  228. {
  229. if(x) *x = clip_x;
  230. if(xx) *xx = clip_xx;
  231. if(y) *y = clip_y;
  232. if(yy) *y = clip_yy;
  233. }
  234. static inline int coord_to_index(unsigned x, unsigned y)
  235. {
  236. if( (x < clip_x) || (x >= clip_xx) || (y < clip_y) || (y >= clip_yy) )
  237. return -1;
  238. return x + (y * XRES);
  239. }
  240. static pixel fgcolor;
  241. static pixel bgcolor;
  242. static unsigned int cursor_x;
  243. static unsigned int cursor_y;
  244. static int ts_calib_left = 0x07F;
  245. static int ts_calib_right = 0x3BD;
  246. static int ts_calib_top = 0x040;
  247. static int ts_calib_bottom = 0x3AA;
  248. static int fontnum;
  249. void set_rawcolor(pixel color)
  250. {
  251. fgcolor = color;
  252. }
  253. void set_bgrawcolor(pixel color)
  254. {
  255. bgcolor = color;
  256. }
  257. static void load_ts_calib()
  258. {
  259. FILE *f;
  260. int retval;
  261. int l,r,t,b;
  262. f = fopen(TOUCHSCREEN_CALIB_FILE, "rb");
  263. if(f)
  264. {
  265. retval = fscanf(f, "%d %d %d %d", &l, &r, &t, &b);
  266. if(retval == 4)
  267. {
  268. ts_calib_left = l;
  269. ts_calib_right = r;
  270. ts_calib_top = t;
  271. ts_calib_bottom = b;
  272. }
  273. fclose(f);
  274. }
  275. }
  276. static void save_ts_calib()
  277. {
  278. FILE *f;
  279. f = fopen(TOUCHSCREEN_CALIB_FILE, "w");
  280. if(f)
  281. {
  282. fprintf(f, "%d %d %d %d\n", ts_calib_left, ts_calib_right, ts_calib_top, ts_calib_bottom);
  283. fclose(f);
  284. }
  285. }
  286. static enum
  287. {
  288. CS_WAIT_RELEASE,
  289. CS_WAIT_PRESS_L,
  290. CS_WAIT_RELEASE_L,
  291. CS_WAIT_PRESS_R,
  292. CS_WAIT_RELEASE_R,
  293. CS_WAIT_PRESS_T,
  294. CS_WAIT_RELEASE_T,
  295. CS_WAIT_PRESS_B,
  296. CS_WAIT_RELEASE_B,
  297. CS_DONE,
  298. } calib_state;
  299. static unsigned long long calib_sum;
  300. static unsigned long calib_count;
  301. int begin_touchscreen_calibration()
  302. {
  303. calib_state = CS_WAIT_RELEASE;
  304. calib_sum = 0;
  305. calib_count = 0;
  306. return 0;
  307. }
  308. #define CALIB_WIDGET_SIZE (32)
  309. int draw_touchscreen_calibration()
  310. {
  311. set_rawcolor(FBCOLOR_WHITE);
  312. cls();
  313. switch(calib_state)
  314. {
  315. case CS_WAIT_RELEASE:
  316. set_rawcolor(FBCOLOR_BLACK);
  317. set_font(2);
  318. set_pos(100,100);
  319. print_string("Calibration", 0);
  320. break;
  321. case CS_WAIT_PRESS_L:
  322. case CS_WAIT_RELEASE_L:
  323. set_rawcolor(FBCOLOR_BLACK);
  324. set_pos(0,YRES / 2);
  325. line_to(CALIB_WIDGET_SIZE, YRES / 2);
  326. set_pos(CALIB_WIDGET_SIZE / 2, (YRES - CALIB_WIDGET_SIZE) / 2);
  327. line_to(CALIB_WIDGET_SIZE / 2, (YRES + CALIB_WIDGET_SIZE) / 2);
  328. break;
  329. case CS_WAIT_PRESS_R:
  330. case CS_WAIT_RELEASE_R:
  331. set_rawcolor(FBCOLOR_BLACK);
  332. set_pos(XRES - CALIB_WIDGET_SIZE, YRES / 2);
  333. line_to(XRES, YRES / 2);
  334. set_pos(XRES - (CALIB_WIDGET_SIZE / 2), (YRES - CALIB_WIDGET_SIZE) / 2);
  335. line_to(XRES - (CALIB_WIDGET_SIZE / 2), (YRES + CALIB_WIDGET_SIZE) / 2);
  336. break;
  337. case CS_WAIT_PRESS_T:
  338. case CS_WAIT_RELEASE_T:
  339. set_rawcolor(FBCOLOR_BLACK);
  340. set_pos(XRES / 2, 0);
  341. line_to(XRES / 2, CALIB_WIDGET_SIZE);
  342. set_pos((XRES - CALIB_WIDGET_SIZE) / 2, CALIB_WIDGET_SIZE / 2);
  343. line_to((XRES + CALIB_WIDGET_SIZE) / 2, CALIB_WIDGET_SIZE / 2);
  344. break;
  345. case CS_WAIT_PRESS_B:
  346. case CS_WAIT_RELEASE_B:
  347. set_rawcolor(FBCOLOR_BLACK);
  348. set_pos(XRES / 2, YRES - CALIB_WIDGET_SIZE);
  349. line_to(XRES / 2, YRES);
  350. set_pos((XRES - CALIB_WIDGET_SIZE) / 2, YRES - (CALIB_WIDGET_SIZE / 2));
  351. line_to((XRES + CALIB_WIDGET_SIZE) / 2, YRES - (CALIB_WIDGET_SIZE / 2));
  352. break;
  353. default:
  354. break;
  355. }
  356. present_framebuffer();
  357. return 0;
  358. }
  359. static int tmp_l, tmp_r, tmp_t, tmp_b;
  360. int advance_touchscreen_calibration(int raw_x, int raw_y, int down)
  361. {
  362. int adj;
  363. switch(calib_state)
  364. {
  365. case CS_WAIT_RELEASE:
  366. if(!down)
  367. {
  368. calib_state++;
  369. }
  370. break;
  371. case CS_WAIT_RELEASE_L:
  372. case CS_WAIT_RELEASE_R:
  373. if(down)
  374. {
  375. calib_sum += raw_x;
  376. calib_count++;
  377. }
  378. else
  379. {
  380. if(calib_count > 16)
  381. {
  382. if(calib_state == CS_WAIT_RELEASE_L)
  383. {
  384. tmp_l = (int)(calib_sum / calib_count);
  385. }
  386. else
  387. {
  388. tmp_r = (int)(calib_sum / calib_count);
  389. }
  390. calib_sum = 0;
  391. calib_count = 0;
  392. calib_state++;
  393. }
  394. }
  395. break;
  396. case CS_WAIT_RELEASE_T:
  397. case CS_WAIT_RELEASE_B:
  398. if(down)
  399. {
  400. calib_sum += raw_y;
  401. calib_count++;
  402. }
  403. else
  404. {
  405. if(calib_count > 16)
  406. {
  407. if(calib_state == CS_WAIT_RELEASE_T)
  408. {
  409. tmp_t = (int)(calib_sum / calib_count);
  410. }
  411. else
  412. {
  413. tmp_b = (int)(calib_sum / calib_count);
  414. }
  415. calib_sum = 0;
  416. calib_count = 0;
  417. calib_state++;
  418. }
  419. }
  420. break;
  421. case CS_WAIT_PRESS_L:
  422. case CS_WAIT_PRESS_R:
  423. case CS_WAIT_PRESS_T:
  424. case CS_WAIT_PRESS_B:
  425. if(down)
  426. {
  427. calib_state++;
  428. }
  429. break;
  430. default:
  431. break;
  432. }
  433. if(calib_state == CS_DONE)
  434. {
  435. adj = ( (tmp_r * CALIB_WIDGET_SIZE / 2) - (tmp_l * CALIB_WIDGET_SIZE / 2) ) / (XRES - CALIB_WIDGET_SIZE);
  436. tmp_l -= adj;
  437. tmp_r += adj;
  438. if(tmp_l < 0)
  439. tmp_l = 0;
  440. if(tmp_l >= tmp_r)
  441. {
  442. calib_state = CS_WAIT_RELEASE;
  443. return 0;
  444. }
  445. adj = ( (tmp_b * CALIB_WIDGET_SIZE / 2) - (tmp_t * CALIB_WIDGET_SIZE / 2) ) / (YRES - CALIB_WIDGET_SIZE);
  446. tmp_t -= adj;
  447. tmp_b += adj;
  448. if(tmp_t < 0)
  449. tmp_b = 0;
  450. if(tmp_t >= tmp_b)
  451. {
  452. calib_state = CS_WAIT_RELEASE;
  453. return 0;
  454. }
  455. ts_calib_left = tmp_l;
  456. ts_calib_right = tmp_r;
  457. ts_calib_top = tmp_t;
  458. ts_calib_bottom = tmp_b;
  459. save_ts_calib();
  460. return 1;
  461. }
  462. return 0;
  463. }
  464. int translate_ts_x(unsigned rawx)
  465. {
  466. int accum = (rawx - ts_calib_left);
  467. if(accum < 0)
  468. accum = 0;
  469. accum *= (XRES - 1);
  470. accum /= (ts_calib_right - ts_calib_left);
  471. if(accum >= XRES)
  472. {
  473. return XRES - 1;
  474. }
  475. return accum;
  476. }
  477. int translate_ts_y(unsigned rawy)
  478. {
  479. int accum = (rawy - ts_calib_top);
  480. if(accum < 0)
  481. accum = 0;
  482. accum *= (YRES - 1);
  483. accum /= (ts_calib_bottom - ts_calib_top);
  484. if(accum >= YRES)
  485. {
  486. return YRES - 1;
  487. }
  488. return accum;
  489. }
  490. static int fbfd = -1;
  491. static pixel *fb = NULL;
  492. #ifdef USE_REMOTE_UI
  493. static inline void dump_fb_shadow(pixel *src)
  494. {
  495. int fb_file;
  496. fb_file = creat(FB_SHADOW_TMP, S_IRUSR | S_IWUSR);
  497. if(fb_file >= 0)
  498. {
  499. write(fb_file, src, sizeof(pixel) * PIXELS);
  500. close(fb_file);
  501. rename(FB_SHADOW_TMP, FB_SHADOW_FILE);
  502. }
  503. }
  504. #else
  505. #define dump_fb_shadow(x)
  506. #endif
  507. // Normally, we want to do all of our drawing operations in a piece of 'mere mortal' (a.k.a. Cacheable)
  508. //system ram pulled off of the heap rather than doing that drawing (lots of little bitty read-modify-write
  509. //operations) to the framebuffer memory which is generally, while mmap()'d into our process space like normal
  510. //ram, marked by the kernel as a very special piece of non-cacheable, DMA-safe low memory, which as a result is
  511. //slow to read/write to and from as A: the CPU can't cache it, and B: even if you have a smart memory controller
  512. //and a multi-path bus, the DMA controller that scans the framebuffer spends most of its time reading this RAM
  513. //(somewhere about 25% of our SOC's total bus bandwidth(!), so we really don't want to get in its way any more
  514. //than we absolutely have to, so it's faster to write to some normal userland memory and then copy it all into
  515. //the actual framebuffer in one shot when we're done drawing. *sigh*, if we only had double buffering and a
  516. //smarter memory controller. On the other hand this runs on a glorified microcontroller, so we take what we
  517. //can get...
  518. #ifdef FRAMEBUFFER_SOFTWARE_BACKBUFFER
  519. static pixel fb_work[PIXELS] = {0};
  520. int present_framebuffer()
  521. {
  522. int i;
  523. int n;
  524. unsigned long *s, *d;
  525. if(!fb)
  526. {
  527. return -1;
  528. }
  529. // printf("Woof!\n");
  530. s = (unsigned long *)fb_work; //grab our source pointer (the backbuffer) as a machine-word sized type
  531. d = (unsigned long *)fb; //and our desination pointer (the framebuffer) " " " " "
  532. n = (PIXELS * sizeof(pixel)) / sizeof(unsigned long); //figure out how many machine words that really is
  533. for(i=0; i < n; i++) //Loop and copy...
  534. {
  535. *d++ = *s++;
  536. }
  537. dump_fb_shadow(fb_work);
  538. return 0;
  539. }
  540. #else //if we have selected to draw directly to the screen without using a software backbuffer
  541. static pixel *fb_work = NULL; //allocate a backbuffer pointer anyway, to later fill with the actual framebuffer
  542. int present_framebuffer() //this function becomes trivial at this point and will probably be optimized out
  543. { //by the compiler, but for interface sanity, we define it anyway...
  544. dump_fb_shadow(fb_work);
  545. return 0;
  546. }
  547. #endif
  548. int open_framebuffer_nondestructive()
  549. {
  550. pixel *foo;
  551. fb = NULL;
  552. fbfd = open(CONFIG_FRAMEBUFFER_PATH, O_RDWR);
  553. if(fbfd < 0)
  554. {
  555. fprintf(stderr, "Cannot open %s\n", CONFIG_FRAMEBUFFER_PATH);
  556. return -1;
  557. }
  558. #ifdef FRAMEBUFFER_RESTORE_PALETTE
  559. if (ioctl(fbfd, FBIOGETCMAP, &old_palette))
  560. {
  561. fprintf(stderr,"FBIOGETCMAP failure\n");
  562. close(fbfd);
  563. fbfd = -1;
  564. return -1;
  565. }
  566. #endif
  567. if (ioctl(fbfd, FBIOPUTCMAP, &our_palette))
  568. {
  569. fprintf(stderr, "FBIOPUTCMAP failed\n");
  570. close(fbfd);
  571. fbfd = -1;
  572. return -1;
  573. }
  574. foo = (pixel *)mmap(NULL, sizeof(pixel) * PIXELS, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
  575. if( (!foo) || (foo == MAP_FAILED))
  576. {
  577. close(fbfd);
  578. fbfd = -1;
  579. fprintf(stderr, "Cannot MMAP framebuffer!\n");
  580. return -2;
  581. }
  582. fb = foo;
  583. #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
  584. //If we have no software backbuffer, assign the backbuffer pointer to point to the real framebuffer
  585. fb_work = fb;
  586. #else
  587. //If we're double buffering, copy the current framebuffer to our backbuffer so we can edit its current contents.
  588. memcpy(fb_work, fb, sizeof(pixel) * PIXELS);
  589. #endif
  590. // We close the file handle in close_framebuffer(), we want to keep it around so we can
  591. //restore the palette to the state we found it in...
  592. set_bgcolor(255,255,255);
  593. set_color(0,0,0);
  594. set_pos(0,0);
  595. load_ts_calib();
  596. return 0;
  597. }
  598. int open_framebuffer()
  599. {
  600. int retval;
  601. //First, open the framebuffer in nondestructive mode...
  602. retval = open_framebuffer_nondestructive();
  603. //If that fails, pass the failure up the call chain
  604. if(retval)
  605. {
  606. return retval;
  607. }
  608. //Otherwise, it's time to clear the screen!
  609. set_color(255,255,255);
  610. set_bgcolor(255,255,255);
  611. cls();
  612. set_color(0,0,0);
  613. set_pos(0,0);
  614. load_ts_calib();
  615. return 0;
  616. }
  617. //If we're trying to close up the framebuffer, we have two things to do:
  618. void close_framebuffer()
  619. {
  620. if(fb) //Release our memory mapping
  621. {
  622. munmap(fb, sizeof(pixel) * PIXELS);
  623. fb = NULL;
  624. }
  625. if(fbfd >= 0) //and restore the color palette back to how we found it...
  626. {
  627. #ifdef FRAMEBUFFER_RESTORE_PALETTE
  628. ioctl(fbfd, FBIOPUTCMAP, &old_palette);
  629. #endif
  630. close(fbfd);
  631. fbfd = -1;
  632. }
  633. }
  634. void set_color(int r, int g, int b)
  635. {
  636. fgcolor = FROM_RGBA(r, g, b, 255);
  637. }
  638. void set_bgcolor(int r, int g, int b)
  639. {
  640. bgcolor = FROM_RGBA(r, g, b, 255);
  641. }
  642. void set_color_t(int r, int g, int b, int a)
  643. {
  644. fgcolor = FROM_RGBA(r, g, b, a);
  645. }
  646. void set_bgcolor_t(int r, int g, int b, int a)
  647. {
  648. bgcolor = FROM_RGBA(r, g, b, a);
  649. }
  650. void set_pos(int x, int y)
  651. {
  652. if(x < 0)
  653. {
  654. cursor_x = 0;
  655. }
  656. else if(x >= XRES)
  657. {
  658. cursor_x = XRES - 1;
  659. }
  660. else
  661. {
  662. cursor_x = x;
  663. }
  664. if(y < 0)
  665. {
  666. cursor_y = 0;
  667. }
  668. else if(y >= YRES)
  669. {
  670. cursor_y = YRES - 1;
  671. }
  672. else
  673. {
  674. cursor_y = y;
  675. }
  676. }
  677. //Plots a point in the current foreground color.
  678. static inline void plot(int x,int y)
  679. {
  680. int index = coord_to_index(x,y);
  681. if(index < 0) return;
  682. fb_work[index] = LOOKUP_BLEND(fgcolor, fb_work[index]);
  683. }
  684. //Plots a point using the foreground color, but forcing the transparent bit on even if it is not
  685. //normally on. This is used for font antialiasing, and probably won't ever be used for much else.
  686. static inline void plot_t(int x, int y)
  687. {
  688. int index = coord_to_index(x,y);
  689. if(index < 0) return;
  690. pixel tmpcolor = (fgcolor | ALPHA_BIT);
  691. fb_work[index] = LOOKUP_BLEND(tmpcolor, fb_work[index]);
  692. }
  693. //Plots a point in the current background color.
  694. static inline void bgplot(int x,int y)
  695. {
  696. int index = coord_to_index(x,y);
  697. if(index < 0) return;
  698. fb_work[index] = LOOKUP_BLEND(bgcolor, fb_work[index]);
  699. }
  700. void line_to(int xdest, int ydest)
  701. {
  702. int tmp;
  703. int x0 = cursor_x;
  704. int y0 = cursor_y;
  705. int x1, y1;
  706. int dx, dy, err, ys;
  707. int x, y;
  708. int steep;
  709. #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
  710. if(!fb_work) { return; }
  711. #endif
  712. if(xdest < 0)
  713. {
  714. xdest = 0;
  715. }
  716. else if(xdest >= XRES)
  717. {
  718. xdest = XRES - 1;
  719. }
  720. if(ydest < 0)
  721. {
  722. ydest = 0;
  723. }
  724. else if(ydest >= YRES)
  725. {
  726. ydest = YRES - 1;
  727. }
  728. x1 = xdest;
  729. y1 = ydest;
  730. steep = abs(y1 - y0) > abs(x1 - x0);
  731. if(steep)
  732. {
  733. SWAP(x0, y0);
  734. SWAP(x1, y1);
  735. }
  736. if(x0 > x1)
  737. {
  738. SWAP(x0, x1);
  739. SWAP(y0, y1);
  740. }
  741. dx = x1 - x0;
  742. err = dx / 2;
  743. dy = abs(y1 - y0);
  744. ys = (y0 < y1)?1:-1;
  745. y = y0;
  746. for(x = x0; x <= x1; x++)
  747. {
  748. if(steep)
  749. {
  750. plot(y,x);
  751. }
  752. else
  753. {
  754. plot(x,y);
  755. }
  756. err -= dy;
  757. if(err < 0)
  758. {
  759. y += ys;
  760. err += dx;
  761. }
  762. }
  763. cursor_x = xdest;
  764. cursor_y = ydest;
  765. }
  766. void draw_sprite(sprite *s)
  767. {
  768. unsigned i, j;
  769. pixel *src;
  770. unsigned int tx, ty;
  771. pixel foo;
  772. int idx;
  773. #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
  774. if(!fb_work) { return; }
  775. #endif
  776. if(!s) { return; }
  777. src = s->data;
  778. for(j = 0; j < s->height; j++)
  779. {
  780. ty = cursor_y + j;
  781. if(ty >= YRES)
  782. {
  783. break;
  784. }
  785. tx = cursor_x;
  786. for(i = 0; i < s->width; i++)
  787. {
  788. foo = *src++;
  789. idx = coord_to_index(tx,ty);
  790. if(idx >= 0)
  791. {
  792. fb_work[idx] = LOOKUP_BLEND(foo, fb_work[idx]);
  793. }
  794. tx++;
  795. }
  796. }
  797. }
  798. void cls()
  799. {
  800. int i, n;
  801. unsigned long pattern;
  802. unsigned long *tgt = (unsigned long *)fb_work;
  803. #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
  804. if(!fb_work) { return; }
  805. #endif
  806. n = sizeof(pattern) / sizeof(pixel); //figure out how many pixels in a word
  807. pattern = 0; //clear the word
  808. for(i=0; i < n; i++) //for each one
  809. {
  810. pattern <<= (sizeof(pixel) * 8); //shift the word over
  811. pattern |= (fgcolor & ~(pixel)ALPHA_BIT); //and clear the alpha bit
  812. }
  813. n = PIXELS / n; //figure out how many iterations we'll need
  814. for(i=0; i < n; i++) //splat the pattern down
  815. {
  816. *tgt++ = pattern;
  817. }
  818. }
  819. void box(int x, int y)
  820. {
  821. int tx = cursor_x;
  822. int ty = cursor_y;
  823. line_to(x, ty);
  824. line_to(x, y);
  825. line_to(tx, y);
  826. line_to(tx, ty);
  827. set_pos(x,y);
  828. }
  829. void box_fill(int x, int y)
  830. {
  831. int i,j;
  832. int t,l,r,b;
  833. #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
  834. if(!fb_work) { return; }
  835. #endif
  836. if(x < 0)
  837. {
  838. x = 0;
  839. }
  840. else if(x >= XRES)
  841. {
  842. x = XRES - 1;
  843. }
  844. else
  845. {
  846. x = x;
  847. }
  848. if(y < 0)
  849. {
  850. y = 0;
  851. }
  852. else if(y >= YRES)
  853. {
  854. y = YRES - 1;
  855. }
  856. else
  857. {
  858. y = y;
  859. }
  860. if(y > cursor_y)
  861. {
  862. t = cursor_y;
  863. b = y;
  864. }
  865. else
  866. {
  867. b = cursor_y;
  868. t = y;
  869. }
  870. if(x > cursor_x)
  871. {
  872. l = cursor_x;
  873. r = x;
  874. }
  875. else
  876. {
  877. r = cursor_x;
  878. l = x;
  879. }
  880. for(j = t; j <= b; j++)
  881. for(i = l; i <= r; i++)
  882. plot(i,j);
  883. cursor_x = x;
  884. cursor_y = y;
  885. }
  886. //---------------------------------------
  887. #define SELECT_FONT(fontnum, fnt) \
  888. switch(fontnum) \
  889. { \
  890. case 0: \
  891. fnt = &smallfont; \
  892. break; \
  893. \
  894. case 1: \
  895. fnt = &medfont; \
  896. break; \
  897. \
  898. case 2: \
  899. fnt = &bigfont; \
  900. break; \
  901. \
  902. default: \
  903. fnt = &smallfont; \
  904. break; \
  905. } \
  906. //---------------------------------------
  907. void font_cell_size(int *w, int *h)
  908. {
  909. fbfont *fnt;
  910. SELECT_FONT(fontnum, fnt)
  911. if(w)
  912. {
  913. *w = fnt->cellwidth;
  914. }
  915. if(h)
  916. {
  917. *h = fnt->cellheight;
  918. }
  919. }
  920. void set_font(unsigned char font)
  921. {
  922. fontnum = font;
  923. }
  924. //This function prints the specified string at the current cursor position.
  925. //If the bkgr parameter is non-zero, background pixels (not occupied by the character itself)
  926. //will be filled in.
  927. void print_string(char *str, int bkgr)
  928. {
  929. fbfont *fnt;
  930. char *c;
  931. int glyphidx;
  932. const char *glyphdata;
  933. int i,j;
  934. int tx, ty;
  935. if(str == NULL) return;
  936. SELECT_FONT(fontnum, fnt) //Get the correct font data for the requested font number
  937. c = str; //set our travelling pointer to the beginning of the string
  938. while(*c) //while we have not hit a terminating '\0'
  939. {
  940. if( (*c < fnt->firstglyph) || (*c > fnt->lastglyph) ) //if we are being asked to draw a glyph we don't have
  941. {
  942. glyphidx = fnt->undefglyph - fnt->firstglyph; //replace it with the font's designated 'undef' glyph
  943. }
  944. else //otherwise, we have the glyph
  945. {
  946. glyphidx = *c - fnt->firstglyph; //compute its index into the glyph table
  947. }
  948. // Next, using that index, use it to compute a pointer offset into the raw font data block
  949. //(i.e. figure out how many bytes we have to index in before we get the first byte that represents
  950. //the drawing instructions for this glyph).
  951. glyphdata = fnt->data + (glyphidx * (fnt->cellwidth * fnt->cellheight));
  952. for(j = 0; j < fnt->cellheight; j++) //For each scan line of the font
  953. {
  954. ty = cursor_y + j; //ty indexes Y of the screen location we're drawing this scan line to
  955. if(ty >= YRES) //if it's off the edge of the screen, save time and skip it
  956. {
  957. break;
  958. }
  959. for(i = 0; i < fnt->cellwidth; i++) //for each pixel in this scan line of the glyph bitmap
  960. {
  961. tx = cursor_x + i; //tx indexes X of the screen location we're drawing this
  962. //pixel of this scan line to
  963. if(tx >= XRES) //if it's off the edge of the screen, ignore it and keep counting
  964. {
  965. glyphdata++; //note that we continue rather than break so we can keep incrementing
  966. continue; //the pointer to the glyph data so we can draw the left half of the next
  967. } //scan line of a glyph that runs off the right edge of the screen
  968. switch(*(glyphdata++)) //see what character represents this pixel in the font map...
  969. {
  970. case ' ': //a ' ' (space) character is a background pixel. Don't plot, unless
  971. if(bkgr) //in background mode, in which case, plot background color.
  972. {
  973. bgplot(tx,ty);
  974. }
  975. break;
  976. case '.': //a '.' (period) character is a blended foreground pixel. If we're in
  977. if(bkgr) //background mode, we need to: (this could be more efficeint, but for clarity
  978. { //I'm keeping it simple):
  979. bgplot(tx,ty); //plot the background first, and then
  980. plot_t(tx,ty); //just plot the translucent foreground pixel
  981. }
  982. else //If we're not in background filling mode,
  983. {
  984. plot_t(tx,ty); //plot the foreground pixel in translucent mode
  985. }
  986. break;
  987. default: //Any other character counts as a solid plot...
  988. plot(tx,ty);
  989. break;
  990. }
  991. }
  992. }
  993. cursor_x += fnt->cellwidth; //Advance the cursor to the next cell
  994. if(cursor_x >= XRES) //If we somehow have run off the end of the screen
  995. {
  996. cursor_x = XRES - 1; //peg our cursor/turtle to the right edge
  997. break; //and don't bother trying to draw the rest of the string
  998. } //(as it will also be off the screen)
  999. c++; //get the next character and do it all again...
  1000. }
  1001. }
  1002. void beep(int fd, int hz, int milis)
  1003. {
  1004. char buffer[64];
  1005. int n;
  1006. n = sprintf(buffer, "/B:%X,%X\r", hz, milis);
  1007. write(fd,buffer,n);
  1008. }
  1009. void set_backlight(int fd, int on)
  1010. {
  1011. char buffer[64];
  1012. int n;
  1013. n = sprintf(buffer, "/D:%c\r", on?'0':'1');
  1014. write(fd,buffer,n);
  1015. }
  1016. void select_blend_mode(int mode)
  1017. {
  1018. switch(mode)
  1019. {
  1020. case BLENDMODE_LIGHT:
  1021. blend_table = light_blend_table;
  1022. break;
  1023. case BLENDMODE_DARK:
  1024. default:
  1025. blend_table = dark_blend_table;
  1026. break;
  1027. }
  1028. }
  1029. void set_alpha_level(unsigned int alpha, unsigned int mode)
  1030. {
  1031. recompute_alpha_lookup(alpha, (mode == BLENDMODE_DARK)?dark_blend_table:light_blend_table);
  1032. }
  1033. /*
  1034. int main()
  1035. {
  1036. int fd;
  1037. char buffer[1024];
  1038. struct pollfd fds[2];
  1039. int retval;
  1040. fd = open_rs232_device("/dev/ttyS1");
  1041. if(fd < 0)
  1042. return fd;
  1043. fds[0].fd = fd;
  1044. fds[0].events = POLLIN;
  1045. open_framebuffer();
  1046. set_color(0,0,255);
  1047. set_pos(100,100);
  1048. box_fill(200,200);
  1049. set_color(0,255,0);
  1050. box(300,300);
  1051. set_pos(150,100);
  1052. set_color(0,0,0);
  1053. set_bgcolor(255,255,0);
  1054. print_string("Hello ",0);
  1055. print_string("World", 1);
  1056. set_font(1);
  1057. set_pos(150,240);
  1058. print_string("Hello ",0);
  1059. print_string("World", 1);
  1060. set_pos(320,240);
  1061. set_color(255,0,0);
  1062. set_backlight(fd,0);
  1063. sleep(1);
  1064. set_backlight(fd,1);
  1065. beep(fd,880,100);
  1066. beep(fd,0,100);
  1067. beep(fd,440,100);
  1068. while(1)
  1069. {
  1070. retval = poll(fds, 1, 10000);
  1071. if(retval < 1)
  1072. {
  1073. printf("Meep!\n");
  1074. continue;
  1075. }
  1076. retval = read(fd, buffer, sizeof(buffer) - 1);
  1077. if(retval > 0)
  1078. {
  1079. int x,y,z;
  1080. buffer[retval] = '\0';
  1081. strip_crlf(buffer);
  1082. printf("Got: \"%s\"\n", buffer);
  1083. if(sscanf(buffer, "/T:%x,%x,%x", &z, &x, &y) == 3)
  1084. {
  1085. if(z)
  1086. {
  1087. x = translate_ts_x(x);
  1088. y = translate_ts_y(y);
  1089. line_to(x,y);
  1090. }
  1091. }
  1092. }
  1093. }
  1094. return 0;
  1095. }
  1096. */