#include #include #include #include #include #include "basic/basic.h" #include "fonts/smallfonts.h" #include "filesystem/ff.h" #include "render.h" /* Global Variables */ const struct FONT_DEF * font = NULL; struct EXTFONT efont; static FIL file; /* current font file */ /* Exported Functions */ void setIntFont(const struct FONT_DEF * newfont){ memcpy(&efont.def,newfont,sizeof(struct FONT_DEF)); efont.type=FONT_INTERNAL; font=&efont.def; }; void setExtFont(const char *fname){ if(strlen(fname)>8+4) return; strcpy(efont.name,fname); // memcpy(efont.name+strlen(fname),".f0n",5); efont.type=FONT_EXTERNAL; font=NULL; }; int getFontHeight(void){ if(font) return font->u8Height; return 8; // XXX: Should be done right. }; static uint8_t read_byte (void) { UINT readbytes; uint8_t byte; f_read(&file, &byte, sizeof(uint8_t), &readbytes); return byte; } int _getFontData(int type, int offset){ UINT readbytes; UINT res; static uint16_t extras; static uint16_t character; // static const void * ptr; if(efont.type == FONT_EXTERNAL){ if (type == START_FONT){ efont.def.u8Width = read_byte (); efont.def.u8Height = read_byte (); efont.def.u8FirstChar = read_byte (); efont.def.u8LastChar = read_byte (); res = f_read(&file, &extras, sizeof(uint16_t), &readbytes); return 0; }; if (type == SEEK_EXTRAS){ f_lseek(&file,6); return 0; }; if(type == GET_EXTRAS){ uint16_t word; res = f_read(&file, &word, sizeof(uint16_t), &readbytes); return word; }; if (type == SEEK_WIDTH){ f_lseek(&file,6+(extras*sizeof(uint16_t))); return 0; }; if(type == GET_WIDTH || type == GET_DATA){ return read_byte (); }; if(type == SEEK_DATA){ character=offset; f_lseek(&file,6+ (extras*sizeof(uint16_t))+ ((extras+font->u8LastChar-font->u8FirstChar)*sizeof(uint8_t))+ (offset*sizeof(uint8_t)) ); return 0; }; if(type == PEEK_DATA){ uint8_t width; width = read_byte (); f_lseek(&file,6+ (extras*sizeof(uint16_t))+ ((extras+font->u8LastChar-font->u8FirstChar)*sizeof(uint8_t))+ (character*sizeof(uint8_t)) ); return width; }; #ifdef NOTYET }else{ // efont.type==FONT_INTERNAL if (type == START_FONT){ memcpy(&efont.def,font,sizeof(struct FONT_DEF)); return 0; }; if (type == SEEK_EXTRAS){ ptr=efont.def.charExtra; return 0; }; if(type == GET_EXTRAS){ uint16_t word; word=*(uint16_t*)ptr; ptr=((uint16_t*)ptr)+1; return word; }; if (type == SEEK_WIDTH){ ptr=efont.def.charInfo; return 0; }; if(type == GET_WIDTH || type == GET_DATA){ uint8_t width; width=*(uint8_t*)ptr; ptr=((uint8_t*)ptr)+1; return width; }; if(type == SEEK_DATA){ if(offset==REPEAT_LAST_CHARACTER) offset=character; else character=offset; ptr=efont.def.au8FontTable; return 0; }; #endif }; /* NOTREACHED */ return 0; }; static int _getIndex(int c){ #define ERRCHR (font->u8FirstChar+1) /* Does this font provide this character? */ if(cu8FirstChar) c=ERRCHR; if(c>font->u8LastChar && efont.type!=FONT_EXTERNAL && font->charExtra == NULL) c=ERRCHR; if(c>font->u8LastChar && (efont.type==FONT_EXTERNAL || font->charExtra != NULL)){ if(efont.type==FONT_EXTERNAL){ _getFontData(SEEK_EXTRAS,0); int cc=0; int cache; while( (cache=_getFontData(GET_EXTRAS,0)) < c) cc++; if( cache > c) c=ERRCHR; else c=font->u8LastChar+cc+1; }else{ int cc=0; while( font->charExtra[cc] < c) cc++; if(font->charExtra[cc] > c) c=ERRCHR; else c=font->u8LastChar+cc+1; }; }; c-=font->u8FirstChar; return c; }; uint8_t charBuf[MAXCHR]; int DoChar(int sx, int sy, int c){ // font=NULL; if(font==NULL){ if(efont.type==FONT_INTERNAL){ font=&efont.def; }else if (efont.type==FONT_EXTERNAL){ UINT res; res=f_open(&file, efont.name, FA_OPEN_EXISTING|FA_READ); if(res){ efont.type=0; font=&Font_7x8; }else{ _getFontData(START_FONT,0); font=&efont.def; }; }else{ font=&Font_7x8; }; }; /* how many bytes is it high? */ char height=(font->u8Height-1)/8+1; char hoff=(8-(font->u8Height%8))%8; const uint8_t * data; int width,preblank=0,postblank=0; do { /* Get Character data */ /* Get intex into character list */ c=_getIndex(c); /* starting offset into character source data */ int toff=0; if(font->u8Width==0){ if(efont.type == FONT_EXTERNAL){ _getFontData(SEEK_WIDTH,0); for(int y=0;y MAXCHR) size = MAXCHR; res = f_read(&file, charBuf, size, &readbytes); if(res != FR_OK || readbytescharInfo[y].widthBits; width=font->charInfo[c].widthBits; toff*=height; data=&font->au8FontTable[toff]; }; postblank=1; }else if(font->u8Width==1){ // NEW CODE if(efont.type == FONT_EXTERNAL){ _getFontData(SEEK_WIDTH,0); for(int y=0;y>4 ==15){ preblank = read_byte (); postblank = read_byte (); width-=3; width/=height; UINT size = width * height; if(size > MAXCHR) size = MAXCHR; res = f_read(&file, charBuf, size, &readbytes); if(res != FR_OK || readbytescharInfo[y].widthBits; width=font->charInfo[c].widthBits; if(font->au8FontTable[toff]>>4 == 15){ // It's a raw character! preblank = font->au8FontTable[toff+1]; postblank= font->au8FontTable[toff+2]; data=&font->au8FontTable[toff+3]; width=(width-3/height); }else{ data=pk_decode(&font->au8FontTable[toff],&width); } }; }else{ toff=(c)*font->u8Width*height; width=font->u8Width; data=&font->au8FontTable[toff]; }; }while(0); /* "real" coordinates. Our physical display is upside down */ #define xy_(x,yb) ( ( (RESY_B-1) -(yb)) * RESX + \ ( (RESX-1) -( x)) ) int x=0; /* raw character data */ int byte; unsigned char mask; /* Our display height is non-integer. Adjust for that. */ sy+=RESY%8; /* Fonts may not be byte-aligned, shift up so the top matches */ sy-=hoff; /* break down the position on byte boundaries */ signed int yidx=sy/8; signed int yoff=sy%8; if(yoff<0) { /* % operator is stupid on negative values */ yoff+=8; yidx-=1; }; sx+=preblank; /* multiple 8-bit-lines */ for(int y=0;y<=height;y++){ if(yidx+y<0) continue; if(yidx+y>=RESY_B) continue; // Number of bits we need to do in this line: int m=yoff+font->u8Height-8*y; m=yoff+height*8-y*8; if(m>8)m=8; if(m<0)m=0; mask=255>>(8-m); // Generate bitmask /* Empty space at top is not to be masked, we consider it not to be part of the font */ if(y==0){ mask=mask<<(yoff+hoff); }else if(y==1 && yoff+hoff>8){ mask=mask<<(yoff+hoff-8); }; if(mask==0) // Optimize :-) continue; flip(mask); /* Optional: empty space to the left */ for(int b=1;b<=preblank;b++){ if(sx-b<0) continue; if(sx-b>=RESX) continue; lcdBuffer[xy_(sx-b,yidx+y)]&=~mask; }; /* Render character */ for(x=0;x>(8-yoff)) | (b2<=RESX) continue; lcdBuffer[xy_(sx+x,yidx+y)]&=~mask; lcdBuffer[xy_(sx+x,yidx+y)]|=byte; }; /* Optional: empty space to the right */ for(int m=0;m=RESX) continue; lcdBuffer[xy_(sx+x+m,yidx+y)]&=~mask; }; }; return sx+(width+postblank); }; #define UTF8 // decode 2 and 3-byte utf-8 strings. #define UT2(a) ( ((a[0]&31)<<6) + (a[1]&63) ) #define UT3(a) ( ((a[0]&15)<<12) + ((a[1]&63)<<6) + (a[2]&63) ) int DoString(int sx, int sy, const char *s){ const char *c; int uc; for(c=s;*c!=0;c++){ #ifdef UTF8 /* will b0rk on non-utf8 */ if((*c&(128+64+32))==(128+64) && c[1]!=0){ uc=UT2(c); c+=1; sx=DoChar(sx,sy,uc); }else if( (*c&(128+64+32+16))==(128+64+32) && c[1]!=0 && c[2] !=0){ uc=UT3(c); c+=2; sx=DoChar(sx,sy,uc); }else #endif sx=DoChar(sx,sy,*c); }; return sx; }; int DoInt(int sx, int sy, int num){ #define mxlen 5 char s[(mxlen+1)]; char * o=s; int len; s[mxlen]=0; char neg=0; if(num<0){ num=-num; neg=1; }; if(num==0){ neg=2; }; for (len=(mxlen-1);len>=0;len--){ s[len]=(num%10)+'0'; if(num==0){ s[len]=' '; // configurable? o=s+len; break; }; num/=10; }; if(neg==1) *o='-'; if(neg==2) *o='0'; if(neg==0) o++; return DoString(sx,sy,o); #undef mxlen }; #define MAX 8 int DoIntXn(int sx, int sy, unsigned int num, unsigned int mxlen){ char s[(MAX+1)]; int len; s[mxlen]=0; for (len=(mxlen-1);len>=0;len--){ s[len]=(num%16)+'0'; if(s[len]>'9') s[len]+='A'-'9'-1; num/=16; }; return DoString(sx,sy,s); }; #undef MAX int DoIntX(int sx, int sy, unsigned int num){ return DoIntXn(sx, sy, num, 8); }; int DoCharX(int sx, int sy, unsigned char num){ return DoIntXn(sx, sy, num, 2); }; int DoShortX(int sx, int sy, uint16_t num){ return DoIntXn(sx, sy, num, 4); };