| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404 |
- /*
- * Copyright (c) 2019 Clementine Computing LLC.
- *
- * This file is part of PopuFare.
- *
- * PopuFare is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * PopuFare is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
- *
- */
- #include <sys/termios.h>
- #include <sys/ioctl.h>
- #include <sys/mman.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <linux/fb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <poll.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <regex.h>
- #include <fcntl.h>
- #include "../common/common_defs.h"
- #include "fbutil.h"
- #include "fbfonts.h"
- extern fbfont smallfont;
- extern fbfont medfont;
- extern fbfont bigfont;
- // This include file contains the palette tables for storing the old palette to be later restored, as well as
- //the palette table we use for our application. It also has a byzantine and insane table where I have factored out
- //all of the possible permutations of painting color X over color Y with or without the blend bit set in color X, so
- //you can use the LOOKUP_BLEND(x, y) macro and it will return the resulting color.
- #include "color_tables.h"
- //-------------------------------
- named_color color_names[] =
- {
- {"white", FBCOLOR_WHITE},
- {"light_gray", FBCOLOR_GRAY},
- {"dark_gray", FBCOLOR_DKGRAY},
- {"black", FBCOLOR_BLACK},
- {"trans_white", FBCOLOR_WHITE | FBCOLOR_TRANSLUCENT},
- {"trans_light_gray", FBCOLOR_GRAY | FBCOLOR_TRANSLUCENT},
- {"trans_dark_gray", FBCOLOR_DKGRAY | FBCOLOR_TRANSLUCENT},
- {"trans_black", FBCOLOR_BLACK | FBCOLOR_TRANSLUCENT},
- {"dark_red", FBCOLOR_DKRED},
- {"red", FBCOLOR_RED},
- {"light_red", FBCOLOR_LTRED},
- {"trans_dark_red", FBCOLOR_DKRED | FBCOLOR_TRANSLUCENT},
- {"trans_red", FBCOLOR_RED | FBCOLOR_TRANSLUCENT},
- {"trans_light_red", FBCOLOR_LTRED | FBCOLOR_TRANSLUCENT},
- {"dark_green", FBCOLOR_DKGREEN},
- {"green", FBCOLOR_GREEN},
- {"light_green", FBCOLOR_LTGREEN},
- {"trans_dark_green", FBCOLOR_DKGREEN | FBCOLOR_TRANSLUCENT},
- {"trans_green", FBCOLOR_GREEN | FBCOLOR_TRANSLUCENT},
- {"trans_light_green", FBCOLOR_LTGREEN | FBCOLOR_TRANSLUCENT},
- {"dark_blue", FBCOLOR_DKBLUE},
- {"blue", FBCOLOR_BLUE},
- {"light_blue", FBCOLOR_LTBLUE},
- {"trans_dark_blue", FBCOLOR_DKBLUE | FBCOLOR_TRANSLUCENT},
- {"trans_blue", FBCOLOR_BLUE | FBCOLOR_TRANSLUCENT},
- {"trans_light_blue", FBCOLOR_LTBLUE | FBCOLOR_TRANSLUCENT},
- {"dark_yellow", FBCOLOR_DKYELLOW},
- {"yellow", FBCOLOR_YELLOW},
- {"light_yellow", FBCOLOR_LTYELLOW},
- {"trans_dark_yellow", FBCOLOR_DKYELLOW | FBCOLOR_TRANSLUCENT},
- {"trans_yellow", FBCOLOR_YELLOW | FBCOLOR_TRANSLUCENT},
- {"trans_light_yellow", FBCOLOR_LTYELLOW | FBCOLOR_TRANSLUCENT},
- {"dark_cyan", FBCOLOR_DKCYAN},
- {"cyan", FBCOLOR_CYAN},
- {"light_cyan", FBCOLOR_LTCYAN},
- {"trans_dark_cyan", FBCOLOR_DKCYAN | FBCOLOR_TRANSLUCENT},
- {"trans_cyan", FBCOLOR_CYAN | FBCOLOR_TRANSLUCENT},
- {"trans_light_cyan", FBCOLOR_LTCYAN | FBCOLOR_TRANSLUCENT},
- {"dark_magenta", FBCOLOR_DKMAGENTA},
- {"magenta", FBCOLOR_MAGENTA},
- {"light_magenta", FBCOLOR_LTMAGENTA},
- {"trans_dark_magenta", FBCOLOR_DKMAGENTA | FBCOLOR_TRANSLUCENT},
- {"trans_magenta", FBCOLOR_MAGENTA | FBCOLOR_TRANSLUCENT},
- {"trans_light_magenta", FBCOLOR_LTMAGENTA | FBCOLOR_TRANSLUCENT},
- {NULL, 0} //THIS TERMINATOR IS NEEDED SO WE DON'T WALK OFF THE END OF THE LIST!
- };
- static inline unsigned int consume_hex_digits(char **s, int digits)
- {
- unsigned int accum = 0;
- int i;
- char *trav;
- if(!s)
- return 0;
- trav = *s;
- if(!trav)
- return 0;
- for(i = 0; i < digits; i++)
- {
- if(!*trav)
- break;
- switch(*trav)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- accum |= (*trav) - '0';
- accum <<= 4;
- trav++;
- break;
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- accum |= (*trav) - '7';
- accum <<= 4;
- trav++;
- break;
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- accum |= (*trav) - 'W';
- accum <<= 4;
- trav++;
- break;
- default:
- *s = trav;
- return accum;
- break;
- }
- }
- *s = trav;
- return accum;
- }
- pixel string_to_color(char *str)
- {
- char *trav;
- pixel color = FBCOLOR_BLACK;
- int i;
- int r = 0, g = 0, b = 0, a = 0xFF;
- if(str)
- {
- trav = str;
- if(*trav == '#') //If we have a numeric color
- {
- trav++;
- i = 0;
- r = consume_hex_digits(&trav, 2); //Get the first hex octet
- if(*trav) //if there are more characters, we'll expect at least #rrggbb
- {
- g = consume_hex_digits(&trav, 2); //covert green
- b = consume_hex_digits(&trav, 2); //and blue
- if(*trav) //if there are still more characters, it may be #rrggbbaa
- {
- a = consume_hex_digits(&trav, 2); //convert alpha
- }
- color = FROM_RGBA(r,g,b,a); //make a framebuffer color from the supplied RGBA values
- }
- else //otherwise, treat the single octet as a raw framebuffer color
- {
- color = r; //if we only got one octet, use it as a raw color
- }
- }
- else //if there was no # to indicate a numeric color, let's scan our list of named colors
- {
- i = 0;
- while(1)
- {
- if(color_names[i].name == NULL) //if we've hit the end of the list
- {
- break; //give up
- }
- if(!strcasecmp(color_names[i].name, trav)) //if it matches
- {
- color = color_names[i].color; //snag the color and we're done
- break;
- }
- else
- {
- i++; //otherwise, try the next one
- }
- }
- }
- }
- return color; //report our results back
- }
- static unsigned int clip_x = 0;
- static unsigned int clip_y = 0;
- static unsigned int clip_xx = XRES;
- static unsigned int clip_yy = YRES;
- void reset_clip_rect()
- {
- clip_x = 0;
- clip_y = 0;
- clip_xx = XRES;
- clip_yy = YRES;
- }
- #define SWAP(a,b) {tmp = a; a = b; b = tmp;}
- void set_clip_rect(unsigned x, unsigned y, unsigned xx, unsigned yy)
- {
- int tmp;
- if(x > xx) SWAP(x, xx);
- if(y > yy) SWAP(y, yy);
- clip_x = (x <= XRES)?x:XRES;
- clip_xx = (xx <= XRES)?xx:XRES;
- clip_y = (y <= YRES)?y:YRES;
- clip_yy = (yy <= YRES)?yy:YRES;
- }
- void get_clip_rect(unsigned *x, unsigned *y, unsigned *xx, unsigned *yy)
- {
- if(x) *x = clip_x;
- if(xx) *xx = clip_xx;
- if(y) *y = clip_y;
- if(yy) *y = clip_yy;
- }
- static inline int coord_to_index(unsigned x, unsigned y)
- {
- if( (x < clip_x) || (x >= clip_xx) || (y < clip_y) || (y >= clip_yy) )
- return -1;
- return x + (y * XRES);
- }
- static pixel fgcolor;
- static pixel bgcolor;
- static unsigned int cursor_x;
- static unsigned int cursor_y;
- static int ts_calib_left = 0x07F;
- static int ts_calib_right = 0x3BD;
- static int ts_calib_top = 0x040;
- static int ts_calib_bottom = 0x3AA;
- static int fontnum;
- void set_rawcolor(pixel color)
- {
- fgcolor = color;
- }
- void set_bgrawcolor(pixel color)
- {
- bgcolor = color;
- }
- static void load_ts_calib()
- {
- FILE *f;
- int retval;
- int l,r,t,b;
- f = fopen(TOUCHSCREEN_CALIB_FILE, "rb");
- if(f)
- {
- retval = fscanf(f, "%d %d %d %d", &l, &r, &t, &b);
- if(retval == 4)
- {
- ts_calib_left = l;
- ts_calib_right = r;
- ts_calib_top = t;
- ts_calib_bottom = b;
- }
- fclose(f);
- }
- }
- static void save_ts_calib()
- {
- FILE *f;
- f = fopen(TOUCHSCREEN_CALIB_FILE, "w");
- if(f)
- {
- fprintf(f, "%d %d %d %d\n", ts_calib_left, ts_calib_right, ts_calib_top, ts_calib_bottom);
- fclose(f);
- }
- }
- static enum
- {
- CS_WAIT_RELEASE,
- CS_WAIT_PRESS_L,
- CS_WAIT_RELEASE_L,
- CS_WAIT_PRESS_R,
- CS_WAIT_RELEASE_R,
- CS_WAIT_PRESS_T,
- CS_WAIT_RELEASE_T,
- CS_WAIT_PRESS_B,
- CS_WAIT_RELEASE_B,
- CS_DONE,
- } calib_state;
- static unsigned long long calib_sum;
- static unsigned long calib_count;
- int begin_touchscreen_calibration()
- {
- calib_state = CS_WAIT_RELEASE;
- calib_sum = 0;
- calib_count = 0;
- return 0;
- }
- #define CALIB_WIDGET_SIZE (32)
- int draw_touchscreen_calibration()
- {
- set_rawcolor(FBCOLOR_WHITE);
- cls();
- switch(calib_state)
- {
- case CS_WAIT_RELEASE:
- set_rawcolor(FBCOLOR_BLACK);
- set_font(2);
- set_pos(100,100);
- print_string("Calibration", 0);
- break;
- case CS_WAIT_PRESS_L:
- case CS_WAIT_RELEASE_L:
- set_rawcolor(FBCOLOR_BLACK);
- set_pos(0,YRES / 2);
- line_to(CALIB_WIDGET_SIZE, YRES / 2);
- set_pos(CALIB_WIDGET_SIZE / 2, (YRES - CALIB_WIDGET_SIZE) / 2);
- line_to(CALIB_WIDGET_SIZE / 2, (YRES + CALIB_WIDGET_SIZE) / 2);
- break;
- case CS_WAIT_PRESS_R:
- case CS_WAIT_RELEASE_R:
- set_rawcolor(FBCOLOR_BLACK);
- set_pos(XRES - CALIB_WIDGET_SIZE, YRES / 2);
- line_to(XRES, YRES / 2);
- set_pos(XRES - (CALIB_WIDGET_SIZE / 2), (YRES - CALIB_WIDGET_SIZE) / 2);
- line_to(XRES - (CALIB_WIDGET_SIZE / 2), (YRES + CALIB_WIDGET_SIZE) / 2);
- break;
- case CS_WAIT_PRESS_T:
- case CS_WAIT_RELEASE_T:
- set_rawcolor(FBCOLOR_BLACK);
- set_pos(XRES / 2, 0);
- line_to(XRES / 2, CALIB_WIDGET_SIZE);
- set_pos((XRES - CALIB_WIDGET_SIZE) / 2, CALIB_WIDGET_SIZE / 2);
- line_to((XRES + CALIB_WIDGET_SIZE) / 2, CALIB_WIDGET_SIZE / 2);
- break;
- case CS_WAIT_PRESS_B:
- case CS_WAIT_RELEASE_B:
- set_rawcolor(FBCOLOR_BLACK);
- set_pos(XRES / 2, YRES - CALIB_WIDGET_SIZE);
- line_to(XRES / 2, YRES);
- set_pos((XRES - CALIB_WIDGET_SIZE) / 2, YRES - (CALIB_WIDGET_SIZE / 2));
- line_to((XRES + CALIB_WIDGET_SIZE) / 2, YRES - (CALIB_WIDGET_SIZE / 2));
- break;
- default:
- break;
- }
- present_framebuffer();
- return 0;
- }
- static int tmp_l, tmp_r, tmp_t, tmp_b;
- int advance_touchscreen_calibration(int raw_x, int raw_y, int down)
- {
- int adj;
- switch(calib_state)
- {
- case CS_WAIT_RELEASE:
- if(!down)
- {
- calib_state++;
- }
- break;
- case CS_WAIT_RELEASE_L:
- case CS_WAIT_RELEASE_R:
- if(down)
- {
- calib_sum += raw_x;
- calib_count++;
- }
- else
- {
- if(calib_count > 16)
- {
- if(calib_state == CS_WAIT_RELEASE_L)
- {
- tmp_l = (int)(calib_sum / calib_count);
- }
- else
- {
- tmp_r = (int)(calib_sum / calib_count);
- }
- calib_sum = 0;
- calib_count = 0;
- calib_state++;
- }
- }
- break;
- case CS_WAIT_RELEASE_T:
- case CS_WAIT_RELEASE_B:
- if(down)
- {
- calib_sum += raw_y;
- calib_count++;
- }
- else
- {
- if(calib_count > 16)
- {
- if(calib_state == CS_WAIT_RELEASE_T)
- {
- tmp_t = (int)(calib_sum / calib_count);
- }
- else
- {
- tmp_b = (int)(calib_sum / calib_count);
- }
- calib_sum = 0;
- calib_count = 0;
- calib_state++;
- }
- }
- break;
- case CS_WAIT_PRESS_L:
- case CS_WAIT_PRESS_R:
- case CS_WAIT_PRESS_T:
- case CS_WAIT_PRESS_B:
- if(down)
- {
- calib_state++;
- }
- break;
- default:
- break;
- }
- if(calib_state == CS_DONE)
- {
- adj = ( (tmp_r * CALIB_WIDGET_SIZE / 2) - (tmp_l * CALIB_WIDGET_SIZE / 2) ) / (XRES - CALIB_WIDGET_SIZE);
- tmp_l -= adj;
- tmp_r += adj;
- if(tmp_l < 0)
- tmp_l = 0;
- if(tmp_l >= tmp_r)
- {
- calib_state = CS_WAIT_RELEASE;
- return 0;
- }
- adj = ( (tmp_b * CALIB_WIDGET_SIZE / 2) - (tmp_t * CALIB_WIDGET_SIZE / 2) ) / (YRES - CALIB_WIDGET_SIZE);
- tmp_t -= adj;
- tmp_b += adj;
- if(tmp_t < 0)
- tmp_b = 0;
- if(tmp_t >= tmp_b)
- {
- calib_state = CS_WAIT_RELEASE;
- return 0;
- }
- ts_calib_left = tmp_l;
- ts_calib_right = tmp_r;
- ts_calib_top = tmp_t;
- ts_calib_bottom = tmp_b;
- save_ts_calib();
- return 1;
- }
- return 0;
- }
- int translate_ts_x(unsigned rawx)
- {
- int accum = (rawx - ts_calib_left);
- if(accum < 0)
- accum = 0;
- accum *= (XRES - 1);
- accum /= (ts_calib_right - ts_calib_left);
- if(accum >= XRES)
- {
- return XRES - 1;
- }
- return accum;
- }
- int translate_ts_y(unsigned rawy)
- {
- int accum = (rawy - ts_calib_top);
- if(accum < 0)
- accum = 0;
- accum *= (YRES - 1);
- accum /= (ts_calib_bottom - ts_calib_top);
- if(accum >= YRES)
- {
- return YRES - 1;
- }
- return accum;
- }
- static int fbfd = -1;
- static pixel *fb = NULL;
- #ifdef USE_REMOTE_UI
- static inline void dump_fb_shadow(pixel *src)
- {
- int fb_file;
- fb_file = creat(FB_SHADOW_TMP, S_IRUSR | S_IWUSR);
- if(fb_file >= 0)
- {
- write(fb_file, src, sizeof(pixel) * PIXELS);
- close(fb_file);
- rename(FB_SHADOW_TMP, FB_SHADOW_FILE);
- }
- }
- #else
- #define dump_fb_shadow(x)
- #endif
- // Normally, we want to do all of our drawing operations in a piece of 'mere mortal' (a.k.a. Cacheable)
- //system ram pulled off of the heap rather than doing that drawing (lots of little bitty read-modify-write
- //operations) to the framebuffer memory which is generally, while mmap()'d into our process space like normal
- //ram, marked by the kernel as a very special piece of non-cacheable, DMA-safe low memory, which as a result is
- //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
- //and a multi-path bus, the DMA controller that scans the framebuffer spends most of its time reading this RAM
- //(somewhere about 25% of our SOC's total bus bandwidth(!), so we really don't want to get in its way any more
- //than we absolutely have to, so it's faster to write to some normal userland memory and then copy it all into
- //the actual framebuffer in one shot when we're done drawing. *sigh*, if we only had double buffering and a
- //smarter memory controller. On the other hand this runs on a glorified microcontroller, so we take what we
- //can get...
- #ifdef FRAMEBUFFER_SOFTWARE_BACKBUFFER
- static pixel fb_work[PIXELS] = {0};
- int present_framebuffer()
- {
- int i;
- int n;
- unsigned long *s, *d;
- if(!fb)
- {
- return -1;
- }
- // printf("Woof!\n");
- s = (unsigned long *)fb_work; //grab our source pointer (the backbuffer) as a machine-word sized type
- d = (unsigned long *)fb; //and our desination pointer (the framebuffer) " " " " "
- n = (PIXELS * sizeof(pixel)) / sizeof(unsigned long); //figure out how many machine words that really is
- for(i=0; i < n; i++) //Loop and copy...
- {
- *d++ = *s++;
- }
- dump_fb_shadow(fb_work);
- return 0;
- }
- #else //if we have selected to draw directly to the screen without using a software backbuffer
- static pixel *fb_work = NULL; //allocate a backbuffer pointer anyway, to later fill with the actual framebuffer
- int present_framebuffer() //this function becomes trivial at this point and will probably be optimized out
- { //by the compiler, but for interface sanity, we define it anyway...
- dump_fb_shadow(fb_work);
- return 0;
- }
- #endif
- int open_framebuffer_nondestructive()
- {
- pixel *foo;
- fb = NULL;
- fbfd = open(CONFIG_FRAMEBUFFER_PATH, O_RDWR);
- if(fbfd < 0)
- {
- fprintf(stderr, "Cannot open %s\n", CONFIG_FRAMEBUFFER_PATH);
- return -1;
- }
- #ifdef FRAMEBUFFER_RESTORE_PALETTE
- if (ioctl(fbfd, FBIOGETCMAP, &old_palette))
- {
- fprintf(stderr,"FBIOGETCMAP failure\n");
- close(fbfd);
- fbfd = -1;
- return -1;
- }
- #endif
- if (ioctl(fbfd, FBIOPUTCMAP, &our_palette))
- {
- fprintf(stderr, "FBIOPUTCMAP failed\n");
- close(fbfd);
- fbfd = -1;
- return -1;
- }
- foo = (pixel *)mmap(NULL, sizeof(pixel) * PIXELS, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
- if( (!foo) || (foo == MAP_FAILED))
- {
- close(fbfd);
- fbfd = -1;
- fprintf(stderr, "Cannot MMAP framebuffer!\n");
- return -2;
- }
- fb = foo;
- #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
- //If we have no software backbuffer, assign the backbuffer pointer to point to the real framebuffer
- fb_work = fb;
- #else
- //If we're double buffering, copy the current framebuffer to our backbuffer so we can edit its current contents.
- memcpy(fb_work, fb, sizeof(pixel) * PIXELS);
- #endif
- // We close the file handle in close_framebuffer(), we want to keep it around so we can
- //restore the palette to the state we found it in...
- set_bgcolor(255,255,255);
- set_color(0,0,0);
- set_pos(0,0);
- load_ts_calib();
- return 0;
- }
- int open_framebuffer()
- {
- int retval;
- //First, open the framebuffer in nondestructive mode...
- retval = open_framebuffer_nondestructive();
- //If that fails, pass the failure up the call chain
- if(retval)
- {
- return retval;
- }
- //Otherwise, it's time to clear the screen!
- set_color(255,255,255);
- set_bgcolor(255,255,255);
- cls();
- set_color(0,0,0);
- set_pos(0,0);
- load_ts_calib();
- return 0;
- }
- //If we're trying to close up the framebuffer, we have two things to do:
- void close_framebuffer()
- {
- if(fb) //Release our memory mapping
- {
- munmap(fb, sizeof(pixel) * PIXELS);
- fb = NULL;
- }
- if(fbfd >= 0) //and restore the color palette back to how we found it...
- {
- #ifdef FRAMEBUFFER_RESTORE_PALETTE
- ioctl(fbfd, FBIOPUTCMAP, &old_palette);
- #endif
- close(fbfd);
- fbfd = -1;
- }
- }
- void set_color(int r, int g, int b)
- {
- fgcolor = FROM_RGBA(r, g, b, 255);
- }
- void set_bgcolor(int r, int g, int b)
- {
- bgcolor = FROM_RGBA(r, g, b, 255);
- }
- void set_color_t(int r, int g, int b, int a)
- {
- fgcolor = FROM_RGBA(r, g, b, a);
- }
- void set_bgcolor_t(int r, int g, int b, int a)
- {
- bgcolor = FROM_RGBA(r, g, b, a);
- }
- void set_pos(int x, int y)
- {
- if(x < 0)
- {
- cursor_x = 0;
- }
- else if(x >= XRES)
- {
- cursor_x = XRES - 1;
- }
- else
- {
- cursor_x = x;
- }
- if(y < 0)
- {
- cursor_y = 0;
- }
- else if(y >= YRES)
- {
- cursor_y = YRES - 1;
- }
- else
- {
- cursor_y = y;
- }
- }
- //Plots a point in the current foreground color.
- static inline void plot(int x,int y)
- {
- int index = coord_to_index(x,y);
- if(index < 0) return;
- fb_work[index] = LOOKUP_BLEND(fgcolor, fb_work[index]);
- }
- //Plots a point using the foreground color, but forcing the transparent bit on even if it is not
- //normally on. This is used for font antialiasing, and probably won't ever be used for much else.
- static inline void plot_t(int x, int y)
- {
- int index = coord_to_index(x,y);
- if(index < 0) return;
- pixel tmpcolor = (fgcolor | ALPHA_BIT);
- fb_work[index] = LOOKUP_BLEND(tmpcolor, fb_work[index]);
- }
- //Plots a point in the current background color.
- static inline void bgplot(int x,int y)
- {
- int index = coord_to_index(x,y);
- if(index < 0) return;
- fb_work[index] = LOOKUP_BLEND(bgcolor, fb_work[index]);
- }
- void line_to(int xdest, int ydest)
- {
- int tmp;
- int x0 = cursor_x;
- int y0 = cursor_y;
- int x1, y1;
- int dx, dy, err, ys;
- int x, y;
- int steep;
- #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
- if(!fb_work) { return; }
- #endif
- if(xdest < 0)
- {
- xdest = 0;
- }
- else if(xdest >= XRES)
- {
- xdest = XRES - 1;
- }
- if(ydest < 0)
- {
- ydest = 0;
- }
- else if(ydest >= YRES)
- {
- ydest = YRES - 1;
- }
- x1 = xdest;
- y1 = ydest;
- steep = abs(y1 - y0) > abs(x1 - x0);
- if(steep)
- {
- SWAP(x0, y0);
- SWAP(x1, y1);
- }
- if(x0 > x1)
- {
- SWAP(x0, x1);
- SWAP(y0, y1);
- }
- dx = x1 - x0;
- err = dx / 2;
- dy = abs(y1 - y0);
- ys = (y0 < y1)?1:-1;
- y = y0;
- for(x = x0; x <= x1; x++)
- {
- if(steep)
- {
- plot(y,x);
- }
- else
- {
- plot(x,y);
- }
- err -= dy;
- if(err < 0)
- {
- y += ys;
- err += dx;
- }
- }
- cursor_x = xdest;
- cursor_y = ydest;
- }
- void draw_sprite(sprite *s)
- {
- unsigned i, j;
- pixel *src;
- unsigned int tx, ty;
- pixel foo;
- int idx;
- #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
- if(!fb_work) { return; }
- #endif
- if(!s) { return; }
- src = s->data;
- for(j = 0; j < s->height; j++)
- {
- ty = cursor_y + j;
- if(ty >= YRES)
- {
- break;
- }
- tx = cursor_x;
- for(i = 0; i < s->width; i++)
- {
- foo = *src++;
- idx = coord_to_index(tx,ty);
- if(idx >= 0)
- {
- fb_work[idx] = LOOKUP_BLEND(foo, fb_work[idx]);
- }
- tx++;
- }
- }
- }
- void cls()
- {
- int i, n;
- unsigned long pattern;
- unsigned long *tgt = (unsigned long *)fb_work;
- #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
- if(!fb_work) { return; }
- #endif
- n = sizeof(pattern) / sizeof(pixel); //figure out how many pixels in a word
- pattern = 0; //clear the word
- for(i=0; i < n; i++) //for each one
- {
- pattern <<= (sizeof(pixel) * 8); //shift the word over
- pattern |= (fgcolor & ~(pixel)ALPHA_BIT); //and clear the alpha bit
- }
- n = PIXELS / n; //figure out how many iterations we'll need
- for(i=0; i < n; i++) //splat the pattern down
- {
- *tgt++ = pattern;
- }
- }
- void box(int x, int y)
- {
- int tx = cursor_x;
- int ty = cursor_y;
- line_to(x, ty);
- line_to(x, y);
- line_to(tx, y);
- line_to(tx, ty);
- set_pos(x,y);
- }
- void box_fill(int x, int y)
- {
- int i,j;
- int t,l,r,b;
- #ifndef FRAMEBUFFER_SOFTWARE_BACKBUFFER
- if(!fb_work) { return; }
- #endif
- if(x < 0)
- {
- x = 0;
- }
- else if(x >= XRES)
- {
- x = XRES - 1;
- }
- else
- {
- x = x;
- }
- if(y < 0)
- {
- y = 0;
- }
- else if(y >= YRES)
- {
- y = YRES - 1;
- }
- else
- {
- y = y;
- }
- if(y > cursor_y)
- {
- t = cursor_y;
- b = y;
- }
- else
- {
- b = cursor_y;
- t = y;
- }
- if(x > cursor_x)
- {
- l = cursor_x;
- r = x;
- }
- else
- {
- r = cursor_x;
- l = x;
- }
- for(j = t; j <= b; j++)
- for(i = l; i <= r; i++)
- plot(i,j);
- cursor_x = x;
- cursor_y = y;
- }
- //---------------------------------------
- #define SELECT_FONT(fontnum, fnt) \
- switch(fontnum) \
- { \
- case 0: \
- fnt = &smallfont; \
- break; \
- \
- case 1: \
- fnt = &medfont; \
- break; \
- \
- case 2: \
- fnt = &bigfont; \
- break; \
- \
- default: \
- fnt = &smallfont; \
- break; \
- } \
- //---------------------------------------
- void font_cell_size(int *w, int *h)
- {
- fbfont *fnt;
- SELECT_FONT(fontnum, fnt)
- if(w)
- {
- *w = fnt->cellwidth;
- }
- if(h)
- {
- *h = fnt->cellheight;
- }
- }
- void set_font(unsigned char font)
- {
- fontnum = font;
- }
- //This function prints the specified string at the current cursor position.
- //If the bkgr parameter is non-zero, background pixels (not occupied by the character itself)
- //will be filled in.
- void print_string(char *str, int bkgr)
- {
- fbfont *fnt;
- char *c;
- int glyphidx;
- const char *glyphdata;
- int i,j;
- int tx, ty;
- if(str == NULL) return;
- SELECT_FONT(fontnum, fnt) //Get the correct font data for the requested font number
- c = str; //set our travelling pointer to the beginning of the string
- while(*c) //while we have not hit a terminating '\0'
- {
- if( (*c < fnt->firstglyph) || (*c > fnt->lastglyph) ) //if we are being asked to draw a glyph we don't have
- {
- glyphidx = fnt->undefglyph - fnt->firstglyph; //replace it with the font's designated 'undef' glyph
- }
- else //otherwise, we have the glyph
- {
- glyphidx = *c - fnt->firstglyph; //compute its index into the glyph table
- }
- // Next, using that index, use it to compute a pointer offset into the raw font data block
- //(i.e. figure out how many bytes we have to index in before we get the first byte that represents
- //the drawing instructions for this glyph).
- glyphdata = fnt->data + (glyphidx * (fnt->cellwidth * fnt->cellheight));
- for(j = 0; j < fnt->cellheight; j++) //For each scan line of the font
- {
- ty = cursor_y + j; //ty indexes Y of the screen location we're drawing this scan line to
- if(ty >= YRES) //if it's off the edge of the screen, save time and skip it
- {
- break;
- }
- for(i = 0; i < fnt->cellwidth; i++) //for each pixel in this scan line of the glyph bitmap
- {
- tx = cursor_x + i; //tx indexes X of the screen location we're drawing this
- //pixel of this scan line to
- if(tx >= XRES) //if it's off the edge of the screen, ignore it and keep counting
- {
- glyphdata++; //note that we continue rather than break so we can keep incrementing
- continue; //the pointer to the glyph data so we can draw the left half of the next
- } //scan line of a glyph that runs off the right edge of the screen
- switch(*(glyphdata++)) //see what character represents this pixel in the font map...
- {
- case ' ': //a ' ' (space) character is a background pixel. Don't plot, unless
- if(bkgr) //in background mode, in which case, plot background color.
- {
- bgplot(tx,ty);
- }
- break;
- case '.': //a '.' (period) character is a blended foreground pixel. If we're in
- if(bkgr) //background mode, we need to: (this could be more efficeint, but for clarity
- { //I'm keeping it simple):
- bgplot(tx,ty); //plot the background first, and then
- plot_t(tx,ty); //just plot the translucent foreground pixel
- }
- else //If we're not in background filling mode,
- {
- plot_t(tx,ty); //plot the foreground pixel in translucent mode
- }
- break;
- default: //Any other character counts as a solid plot...
- plot(tx,ty);
- break;
- }
- }
- }
- cursor_x += fnt->cellwidth; //Advance the cursor to the next cell
- if(cursor_x >= XRES) //If we somehow have run off the end of the screen
- {
- cursor_x = XRES - 1; //peg our cursor/turtle to the right edge
- break; //and don't bother trying to draw the rest of the string
- } //(as it will also be off the screen)
- c++; //get the next character and do it all again...
- }
- }
- void beep(int fd, int hz, int milis)
- {
- char buffer[64];
- int n;
- n = sprintf(buffer, "/B:%X,%X\r", hz, milis);
- write(fd,buffer,n);
- }
- void set_backlight(int fd, int on)
- {
- char buffer[64];
- int n;
- n = sprintf(buffer, "/D:%c\r", on?'0':'1');
- write(fd,buffer,n);
- }
- void select_blend_mode(int mode)
- {
- switch(mode)
- {
- case BLENDMODE_LIGHT:
- blend_table = light_blend_table;
- break;
- case BLENDMODE_DARK:
- default:
- blend_table = dark_blend_table;
- break;
- }
- }
- void set_alpha_level(unsigned int alpha, unsigned int mode)
- {
- recompute_alpha_lookup(alpha, (mode == BLENDMODE_DARK)?dark_blend_table:light_blend_table);
- }
- /*
- int main()
- {
- int fd;
- char buffer[1024];
- struct pollfd fds[2];
- int retval;
- fd = open_rs232_device("/dev/ttyS1");
- if(fd < 0)
- return fd;
- fds[0].fd = fd;
- fds[0].events = POLLIN;
- open_framebuffer();
- set_color(0,0,255);
- set_pos(100,100);
- box_fill(200,200);
- set_color(0,255,0);
- box(300,300);
- set_pos(150,100);
- set_color(0,0,0);
- set_bgcolor(255,255,0);
- print_string("Hello ",0);
- print_string("World", 1);
- set_font(1);
- set_pos(150,240);
- print_string("Hello ",0);
- print_string("World", 1);
- set_pos(320,240);
- set_color(255,0,0);
- set_backlight(fd,0);
- sleep(1);
- set_backlight(fd,1);
- beep(fd,880,100);
- beep(fd,0,100);
- beep(fd,440,100);
- while(1)
- {
- retval = poll(fds, 1, 10000);
- if(retval < 1)
- {
- printf("Meep!\n");
- continue;
- }
- retval = read(fd, buffer, sizeof(buffer) - 1);
- if(retval > 0)
- {
- int x,y,z;
- buffer[retval] = '\0';
- strip_crlf(buffer);
- printf("Got: \"%s\"\n", buffer);
- if(sscanf(buffer, "/T:%x,%x,%x", &z, &x, &y) == 3)
- {
- if(z)
- {
- x = translate_ts_x(x);
- y = translate_ts_y(y);
- line_to(x,y);
- }
- }
- }
- }
- return 0;
- }
- */
|