diff --git a/include/arm11/acf.h b/include/arm11/acf.h index 91e8ea1..217d66c 100644 --- a/include/arm11/acf.h +++ b/include/arm11/acf.h @@ -2,6 +2,9 @@ #define _ANOD_COMPILED_FONT_H_ #include +#include +#include +#include #define ACFONT_NOT_FOUND -1 #define ACFONT_INVALID -2 @@ -12,63 +15,15 @@ extern int acf_set_font(const char *); extern const char *acf_draw(int, int, unsigned, unsigned, unsigned, const char *); -#include "arm11/acf_dev.h" -#include "arm11/acf_cfg.h" - -#if ACF_CANVAS == ACFDEV_U8GBITMAP - -#include "c_stdint.h" -#include "c_stdio.h" -#include "c_stdlib.h" -#include "c_string.h" - -extern uint8_t *acfCanvas; - -#include "vfs.h" - -#define ACF_BYTE_SIZE 8 -#define ACF_CANVAS_SIZE(w, h) ((w) * (h) / ACF_BYTE_SIZE) -#define ACF_BYTE_WIDTH(w, h) ((w) / ACF_BYTE_SIZE) -#define ACF_BYTE_OFFSET(x, y, w, h) (((h) - (y)-1) * ACF_BYTE_WIDTH(w, h) + (x) / ACF_BYTE_SIZE) -#define ACF_U8G_BMP_BIT(x, y) (1 << (7 - (x) % 8)) - -#define FILE_T int -#define FILE_OPEN(path, mode) vfs_open(path, mode) -#define FILE_READ(f, pos, size) vfs_read(f, pos, size) -#define FILE_SEEK(f,p) vfs_lseek(f,p,VFS_SEEK_SET) -#define FILE_SEEKEND(f) vfs_lseek(f,0,VFS_SEEK_END) -#define FILE_TELL(f) vfs_tell(f) - -#define ACF_LIT_POINT(x, y, w, h, islit) \ - { \ - if (0 <= (x) && (x) < w && 0 <= (y) && (y) < h) \ - { \ - if ((islit)) \ - acfCanvas[ACF_BYTE_OFFSET(x, y, w, h)] |= ACF_U8G_BMP_BIT(x, y); \ - else \ - acfCanvas[ACF_BYTE_OFFSET(x, y, w, h)] &= ~ACF_U8G_BMP_BIT(x, y); \ - } \ +#define ACF_LIT_POINT(x, y, w, h, islit) \ + { \ + if (0 <= (x) && (x) < w && 0 <= (y) && (y) < h) \ + { \ + if ((islit)) \ + { \ + frame[(x) + (y) * (w)] = 1; \ + } \ + } \ } -#elif ACF_CANVAS == ACFDEV_OPENAGB - -#include -#include -#include -#include -#include "arm11/console.h" - -#include "fs.h" - -#define ACF_LIT_POINT(x, y, w, h, islit) \ - { \ - if (0 <= (x) && (x) < w && 0 <= (y) && (y) < h) \ - { \ - if ((islit)) \ - frame[240*y + x] |= color; \ - } \ - } - -#else -#endif #endif //_ANOD_COMPILED_FONT_H_ diff --git a/source/arm11/acf.c b/source/arm11/acf.c index 4b4246f..97f523d 100644 --- a/source/arm11/acf.c +++ b/source/arm11/acf.c @@ -5,43 +5,51 @@ * 3数据,每个数据是前4个字节的bbx,第5个字节的前7位是DWIDTH的x分量,后1位0表示位图每次读取1字节,为1表示每次读取2字节。第6个字节及以后是BITMAP的数据,总长度是bbx[1]的长度。 */ -#include "arm11/acf.h" +#include "acf.h" // 画点函数 #ifndef ACF_LIT_POINT #error "ACF_LIT_POINT SHOULD BE DECLARE BEFORE USING GB2312 FONT" #endif +extern uint8_t canvas[]; + +typedef struct +{ + uint16_t start; + uint16_t end; + uint8_t padding; + uint8_t bbxdcnt; +} Fragment; + typedef struct { uint8_t width; uint8_t height; int8_t offsetx; int8_t offsety; - uint16_t amount; char *filename; - uint16_t *chapter; uint32_t filesize; + uint16_t fragsize; + Fragment *fragments; } ACFont; static ACFont gblfont = { - 0, 0, 0, 0, 0, NULL, NULL, 0}; + 0, 0, 0, 0, NULL, 0, 0, NULL +}; -#define ACFONT_HEAD_SIZE 6 -#define ACFONT_HEAD_AMOUNT(buf) ((buf)[0] + (buf)[1] * 0x100) -#define ACFONT_HEAD_WIDTH(buf) ((buf)[2]) -#define ACFONT_HEAD_HEIGHT(buf) ((buf)[3]) -#define ACFONT_HEAD_OFFSETX(buf) ((int8_t)(buf)[4]) -#define ACFONT_HEAD_OFFSETY(buf) ((int8_t)(buf)[5]) +#define ACFONT_HEAD_SIZE 10u +#define ACFONT_HEAD_MAGNO 0x02464341u +#define ACFONT_HEAD_WIDTH(buf) ((buf)[4]) +#define ACFONT_HEAD_HEIGHT(buf) ((buf)[5]) +#define ACFONT_HEAD_OFFSETX(buf) ((int8_t)(buf)[6]) +#define ACFONT_HEAD_OFFSETY(buf) ((int8_t)(buf)[7]) +#define ACFONT_HEAD_MEMFRAG(buf) (*(uint16_t*)( (buf)+8 )) -#define ACFONT_SIZEOF_INDEX 5 -#define ACFONT_INDEX(n) (ACFONT_HEAD_SIZE + (n)*ACFONT_SIZEOF_INDEX) -#define ACFONT_INDEX_VALUE(data) (0x10000 * data[2] + data[3] + data[4] * 0x100) +#define ACFONT_SIZEOF_BBX 4u +#define ACFONT_SIZEOF_GLYPH 64u -#define ACFONT_SIZEOF_BBX 4 -#define ACFONT_SIZEOF_GLYPH 64 - -#define ACFONT_CHAPTER_MEMORY 480 +#define ACFONT_BBXD_FROM_FRAG(pFrag, idx) (uint8_t*)( (uint8_t*)(pFrag) + sizeof(Fragment) + ACFONT_SIZEOF_BBX*(idx) ) // 提供两个方法: // 1 设置字体文件名称 @@ -51,87 +59,78 @@ static ACFont gblfont = { int acf_set_font(const char *acfile) { // open the font file - FHandle font; - u32 readed; - if( RES_OK != fOpen(&font, acfile, FA_READ) ) + FILE *font; + uint32_t readed; + if( ( font = fopen(acfile, "rb") ) == NULL ) return ACFONT_NOT_FOUND; // 读取数据 uint8_t head[ACFONT_HEAD_SIZE]; - if( RES_OK != fRead(font, head, ACFONT_HEAD_SIZE, &readed) || - readed != ACFONT_HEAD_SIZE ) + readed = fread(head, 1, ACFONT_HEAD_SIZE, font); + if( readed != ACFONT_HEAD_SIZE ) { - fClose(font); + fclose(font); return ACFONT_INVALID; } - if (ACFONT_SIZEOF_BBX + ACFONT_HEAD_HEIGHT(head) * ACFONT_HEAD_WIDTH(head) / 8 > ACFONT_SIZEOF_GLYPH) + if ( *(uint32_t*)(head) != ACFONT_HEAD_MAGNO ) { - fClose(font); + fclose(font); return ACFONT_NOT_SUPPORT; } // assign basic data from file - gblfont.amount = ACFONT_HEAD_AMOUNT(head); gblfont.width = ACFONT_HEAD_WIDTH(head); gblfont.height = ACFONT_HEAD_HEIGHT(head); gblfont.offsetx = ACFONT_HEAD_OFFSETX(head); gblfont.offsety = ACFONT_HEAD_OFFSETY(head); // get filesize - gblfont.filesize = fSize(font); + fseek(font, 0, SEEK_END); + gblfont.filesize = ftell(font); if (gblfont.filename != NULL) + { free(gblfont.filename); - if (gblfont.chapter != NULL) - free(gblfont.chapter); + gblfont.filename = NULL; + } + if (gblfont.fragments) + { + free( gblfont.fragments ); + gblfont.fragments = NULL; + } + + if( 0 != fseek(font, ACFONT_HEAD_SIZE, SEEK_SET) ) + { + fclose( font ); + return ACFONT_INVALID; + } // get index chapters // 1 decide chapter count - const int nparts = ACFONT_CHAPTER_MEMORY / ACFONT_SIZEOF_INDEX; - int nchapter = gblfont.amount / nparts; - if (nchapter * nparts < gblfont.amount) + uint16_t memfrag = ACFONT_HEAD_MEMFRAG(head); + uint8_t *fragments = (uint8_t*)malloc(memfrag); + if( fragments == NULL ) { - ++nchapter; - } - - // 2 alloc cache for chapter - uint16_t *pchapter = (uint16_t *)malloc(nchapter * sizeof(uint16_t)); - if (pchapter == NULL) - { - memset(&gblfont, 0, sizeof(gblfont)); - fClose(font); + fclose(font); return ACFONT_MEM_EMPTY; } - - // 3 load chapter to cache - for (int i = 0; i < nchapter; ++i) + + readed = fread(fragments, 1, memfrag, font); + if( readed != memfrag ) { - int pos = ACFONT_INDEX(i * nparts); - if( RES_OK != fLseek(font, pos) ) - { - free(pchapter); - fClose(font); - return ACFONT_INVALID; - } - if( RES_OK != fRead(font, head, 2, &readed) || - readed != 2 ) - { - free(pchapter); - fClose(font); - return ACFONT_READ_EOF; - } - pchapter[i] = head[0] | (head[1] << 8); + free( fragments ); + fclose(font); + return ACFONT_INVALID; } - gblfont.chapter = pchapter; // save filename for `fopen` int len = strlen(acfile); char *file = (char *)malloc(len + 1); if (file == NULL) { - free(gblfont.chapter); + free( fragments ); memset(&gblfont, 0, sizeof(gblfont)); - fClose(font); + fclose(font); return ACFONT_MEM_EMPTY; } @@ -139,7 +138,10 @@ int acf_set_font(const char *acfile) file[len] = 0; gblfont.filename = file; - fClose(font); + gblfont.fragments = (Fragment*)fragments; + gblfont.fragsize = memfrag; + + fclose(font); return 0; } @@ -188,86 +190,36 @@ static inline const char *next_unicode(const char *utf8, uint32_t *code) return utf8; } -static int bsearch_font(FHandle fd, uint32_t unicode) +static int bsearch_font(FILE *fd, uint32_t unicode, Fragment **pFrag) { - u32 readed; - - // decide chapter count - const int nparts = ACFONT_CHAPTER_MEMORY / ACFONT_SIZEOF_INDEX; - int nchapter = gblfont.amount / nparts; - if (nchapter * nparts < gblfont.amount) + int retval = 0; + uint8_t *memory = (uint8_t*)gblfont.fragments; + for( int i=0; i < gblfont.fragsize; ) { - ++nchapter; - } - - int min = 0, max = nchapter; - int m, found = 0; - - // search in chapter - for (m = (min + max) >> 1; min < m; m = (min + max) >> 1) - { - uint16_t code = gblfont.chapter[m]; - if (unicode < code) - max = m; - else if (code < unicode) - min = m; - else - { - found = 1; - break; + Fragment *frag = (Fragment*)&memory[i]; + if( frag->start <= unicode ) { + if( unicode <= frag->end ) + { + // hit + int diff = unicode - frag->start; + *pFrag = frag; + return retval + frag->padding * diff; + } + else { + retval += frag->padding * (frag->end - frag->start + 1); + i += sizeof(Fragment) + ACFONT_SIZEOF_BBX * frag->bbxdcnt; + } } + else return ACFONT_NOT_FOUND; } - - if (found) - { - uint8_t v[ACFONT_SIZEOF_INDEX]; - if( RES_OK != fLseek(fd, ACFONT_INDEX(nparts * m)) ) - return ACFONT_INVALID; - - if( RES_OK != fRead(fd, v, ACFONT_SIZEOF_INDEX, &readed) || - readed != ACFONT_SIZEOF_INDEX ) - return ACFONT_READ_EOF; - - return ACFONT_INDEX_VALUE(v); - } - - // not match in chapter, search in chapter's parts - int len = m + 1 == nchapter ? (gblfont.amount % nparts) : nparts; - int size = len * ACFONT_SIZEOF_INDEX; - if( RES_OK != fLseek( fd, ACFONT_INDEX( nparts * m) ) ) - return ACFONT_INVALID; - - uint8_t *cache = (uint8_t *)malloc(size); - if( RES_OK != fRead(fd, cache, size, &readed) || - readed != (u32)size ) - { - free(cache); - return ACFONT_READ_EOF; - } - - for (min = 0, max = len, m = len >> 1; - min < m; - m = (min + max) >> 1) - { - int idx = m * ACFONT_SIZEOF_INDEX; - uint16_t code = cache[idx] | (cache[idx + 1] << 8); - if (unicode < code) - max = m; - else if (code < unicode) - min = m; - else - { - uint8_t *index = &cache[idx]; - found = ACFONT_INDEX_VALUE(index); - break; - } - } - - free(cache); - return found ? found : -1; + return ACFONT_NOT_FOUND; } -#define BIT_AT_POS(mem, idx) ((mem)[(idx) / 8] & (1 << ((idx) % 8))) +#define BIT_PER_BYTE 8 + +#define BIT_AT_POS(mem, idx) ((mem)[(idx) / BIT_PER_BYTE] & (1 << ((idx) % BIT_PER_BYTE))) +#define SET_AT_POS(mem, idx) ((mem)[(idx) / BIT_PER_BYTE] |= (1 << ((idx) % BIT_PER_BYTE)) ) + #define SIZEOF_S6 6 static inline int readS6(uint8_t *p, int index) { @@ -283,38 +235,54 @@ static inline int readS6(uint8_t *p, int index) return symbol ? -ret : ret; } -static int render_unicode(FHandle fd, int *x, int *y, unsigned width, unsigned height, uint32_t code, unsigned *width_max) +#define PIX_IN_LINE(x,y,w) (x) + (y)*(w) +static int render_unicode(FILE *fd, int *x, unsigned width, unsigned height, uint32_t code, unsigned *width_max, uint8_t *ram) { - u32 readed; - u16 color = consoleGetFgColor(); - u16 *frame = consoleGetDefault()->frameBuffer; + uint32_t readed; // 获取code对应的字体信息 - int font_pos = bsearch_font(fd, code); + Fragment *frag; + int font_pos = bsearch_font(fd, code, &frag); if (font_pos < 0) - return 0; + { + return -1; + } + font_pos += ACFONT_HEAD_SIZE + gblfont.fragsize; if ((uint32_t)font_pos > gblfont.filesize) - return 0; - font_pos += ACFONT_HEAD_SIZE + gblfont.amount * ACFONT_SIZEOF_INDEX; + { + return -2; + } - uint8_t font[ACFONT_SIZEOF_GLYPH]; - if( RES_OK != fLseek(fd, font_pos) ) - return 1; + uint8_t font[ACFONT_SIZEOF_GLYPH], *glyph; + if( 0 != fseek(fd, font_pos, SEEK_SET) ) + return -3; - if( RES_OK != fRead(fd, font, ACFONT_SIZEOF_GLYPH, &readed) || - (readed != ACFONT_SIZEOF_GLYPH && (uint32_t)font_pos + ACFONT_SIZEOF_GLYPH < gblfont.filesize) ) - return 1; + readed = fread(font, 1, frag->padding, fd); + if( readed != (uint32_t)frag->padding ) + return -4; - int8_t bbx[4]; - bbx[0] = readS6(font, 0); - bbx[1] = readS6(font, SIZEOF_S6); - bbx[2] = readS6(font, SIZEOF_S6 * 2); - bbx[3] = readS6(font, SIZEOF_S6 * 3); - int fw = readS6(font, SIZEOF_S6 * 4); + int8_t bbx[4], fw; + uint8_t *bbxd; + if( frag->bbxdcnt == 1 ) + { + bbxd = ACFONT_BBXD_FROM_FRAG(frag, 0); + glyph = font; + } + else + { + uint8_t index = font[0]; + bbxd = ACFONT_BBXD_FROM_FRAG(frag, index); + glyph = font+1; + } + bbx[0] = readS6(bbxd, 0); + bbx[1] = readS6(bbxd, SIZEOF_S6); + bbx[2] = readS6(bbxd, SIZEOF_S6 * 2); + bbx[3] = readS6(bbxd, SIZEOF_S6 * 3); + fw = readS6(bbxd, SIZEOF_S6 * 4); // render // 从上往下(y从大到小,x从小到大)进行绘制 - int px = *x, py = *y; // px/py不参与计算位置 + int px = *x, py = 0-gblfont.offsety; // px/py不参与计算位置 int cx = px + bbx[2], cy = py + bbx[1] + bbx[3]; // cx/cy计算位置进行绘制 // 先检查宽度 @@ -326,45 +294,73 @@ static int render_unicode(FHandle fd, int *x, int *y, unsigned width, unsigned h { for (int j = 0; j < bbx[0]; ++j) { - ACF_LIT_POINT(cx + j, cy - i, (int)width, (int)height, BIT_AT_POS(font + 4, bbx[0] * i + j)); + if( 0 <= i && i < height && 0 <= j && j < width ) + { + if( BIT_AT_POS(glyph, bbx[0] * i + j) ) + { + SET_AT_POS( ram, PIX_IN_LINE(cx+j, cy-i, width) ); + } + } } } - + // 更新 *x = px + fw; - *y = py; return 0; } // 根据字体绘制中文字符 // x,y - 绘制一行字符的基准点 -// width - 最长绘制多少个像素点,填0则忽略此参数 +// maxwidth - 最长绘制多少个像素点,填0则忽略此参数 // utf8_line - utf8字符串 // 返回:第一个未绘制的字符的位置,如果width为0,则返回永远是NULL const char *acf_draw(int x, int y, unsigned width, unsigned height, unsigned maxwidth, const char *utf8_line) { - u32 font; - if( gblfont.filename == NULL || RES_OK != fOpen(&font, gblfont.filename, FA_READ) ) + FILE *font; + int linex = 0; + if( gblfont.filename == NULL || (font = fopen(gblfont.filename, "rb")) == NULL ) { // log return utf8_line; } uint32_t unicode; + if( maxwidth == 0 ) maxwidth = width; unsigned *option = width == 0 ? NULL : &maxwidth; + + const int ramsize = gblfont.height * maxwidth / BIT_PER_BYTE; + uint8_t *localram = malloc( ramsize ); + memset( localram, 0, ramsize ); + for (const char *next = next_unicode(utf8_line, &unicode); next != NULL; next = next_unicode(utf8_line, &unicode)) { - int error = render_unicode(font, &x, &y, width, height, unicode, option); + int error = render_unicode(font, &linex, maxwidth, height, unicode, option, localram); if (error) { - fClose(font); + free( localram ); + fclose(font); return utf8_line; } utf8_line = next; } - fClose(font); + + // copy back to canvas + uint8_t *frame = canvas; + for( int i=0; i < gblfont.height; ++i ) + { + for( int j=0; j < maxwidth; ++j ) + { + if( BIT_AT_POS(localram, PIX_IN_LINE(j, i, maxwidth)) ) + { + ACF_LIT_POINT(x+j, y+(gblfont.height-1-i), width, height, 1); + } + } + } + + free( localram ); + fclose(font); return NULL; }