ACF进化到了acf2,所以需要更新代码

This commit is contained in:
anod 2022-08-09 17:36:20 +08:00
parent c4f39b7e9e
commit 1337e38256
2 changed files with 175 additions and 224 deletions

View File

@ -2,6 +2,9 @@
#define _ANOD_COMPILED_FONT_H_ #define _ANOD_COMPILED_FONT_H_
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ACFONT_NOT_FOUND -1 #define ACFONT_NOT_FOUND -1
#define ACFONT_INVALID -2 #define ACFONT_INVALID -2
@ -12,63 +15,15 @@
extern int acf_set_font(const char *); extern int acf_set_font(const char *);
extern const char *acf_draw(int, int, unsigned, unsigned, unsigned, const char *); extern const char *acf_draw(int, int, unsigned, unsigned, unsigned, const char *);
#include "arm11/acf_dev.h" #define ACF_LIT_POINT(x, y, w, h, islit) \
#include "arm11/acf_cfg.h" { \
if (0 <= (x) && (x) < w && 0 <= (y) && (y) < h) \
#if ACF_CANVAS == ACFDEV_U8GBITMAP { \
if ((islit)) \
#include "c_stdint.h" { \
#include "c_stdio.h" frame[(x) + (y) * (w)] = 1; \
#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); \
} \
} }
#elif ACF_CANVAS == ACFDEV_OPENAGB
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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_ #endif //_ANOD_COMPILED_FONT_H_

View File

@ -5,43 +5,51 @@
* 34bbx57DWIDTH的x分量101126BITMAP的数据bbx[1] * 34bbx57DWIDTH的x分量101126BITMAP的数据bbx[1]
*/ */
#include "arm11/acf.h" #include "acf.h"
// 画点函数 // 画点函数
#ifndef ACF_LIT_POINT #ifndef ACF_LIT_POINT
#error "ACF_LIT_POINT SHOULD BE DECLARE BEFORE USING GB2312 FONT" #error "ACF_LIT_POINT SHOULD BE DECLARE BEFORE USING GB2312 FONT"
#endif #endif
extern uint8_t canvas[];
typedef struct
{
uint16_t start;
uint16_t end;
uint8_t padding;
uint8_t bbxdcnt;
} Fragment;
typedef struct typedef struct
{ {
uint8_t width; uint8_t width;
uint8_t height; uint8_t height;
int8_t offsetx; int8_t offsetx;
int8_t offsety; int8_t offsety;
uint16_t amount;
char *filename; char *filename;
uint16_t *chapter;
uint32_t filesize; uint32_t filesize;
uint16_t fragsize;
Fragment *fragments;
} ACFont; } ACFont;
static ACFont gblfont = { 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_SIZE 10u
#define ACFONT_HEAD_AMOUNT(buf) ((buf)[0] + (buf)[1] * 0x100) #define ACFONT_HEAD_MAGNO 0x02464341u
#define ACFONT_HEAD_WIDTH(buf) ((buf)[2]) #define ACFONT_HEAD_WIDTH(buf) ((buf)[4])
#define ACFONT_HEAD_HEIGHT(buf) ((buf)[3]) #define ACFONT_HEAD_HEIGHT(buf) ((buf)[5])
#define ACFONT_HEAD_OFFSETX(buf) ((int8_t)(buf)[4]) #define ACFONT_HEAD_OFFSETX(buf) ((int8_t)(buf)[6])
#define ACFONT_HEAD_OFFSETY(buf) ((int8_t)(buf)[5]) #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_SIZEOF_BBX 4u
#define ACFONT_INDEX(n) (ACFONT_HEAD_SIZE + (n)*ACFONT_SIZEOF_INDEX) #define ACFONT_SIZEOF_GLYPH 64u
#define ACFONT_INDEX_VALUE(data) (0x10000 * data[2] + data[3] + data[4] * 0x100)
#define ACFONT_SIZEOF_BBX 4 #define ACFONT_BBXD_FROM_FRAG(pFrag, idx) (uint8_t*)( (uint8_t*)(pFrag) + sizeof(Fragment) + ACFONT_SIZEOF_BBX*(idx) )
#define ACFONT_SIZEOF_GLYPH 64
#define ACFONT_CHAPTER_MEMORY 480
// 提供两个方法: // 提供两个方法:
// 1 设置字体文件名称 // 1 设置字体文件名称
@ -51,87 +59,78 @@ static ACFont gblfont = {
int acf_set_font(const char *acfile) int acf_set_font(const char *acfile)
{ {
// open the font file // open the font file
FHandle font; FILE *font;
u32 readed; uint32_t readed;
if( RES_OK != fOpen(&font, acfile, FA_READ) ) if( ( font = fopen(acfile, "rb") ) == NULL )
return ACFONT_NOT_FOUND; return ACFONT_NOT_FOUND;
// 读取数据 // 读取数据
uint8_t head[ACFONT_HEAD_SIZE]; uint8_t head[ACFONT_HEAD_SIZE];
if( RES_OK != fRead(font, head, ACFONT_HEAD_SIZE, &readed) || readed = fread(head, 1, ACFONT_HEAD_SIZE, font);
readed != ACFONT_HEAD_SIZE ) if( readed != ACFONT_HEAD_SIZE )
{ {
fClose(font); fclose(font);
return ACFONT_INVALID; 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; return ACFONT_NOT_SUPPORT;
} }
// assign basic data from file // assign basic data from file
gblfont.amount = ACFONT_HEAD_AMOUNT(head);
gblfont.width = ACFONT_HEAD_WIDTH(head); gblfont.width = ACFONT_HEAD_WIDTH(head);
gblfont.height = ACFONT_HEAD_HEIGHT(head); gblfont.height = ACFONT_HEAD_HEIGHT(head);
gblfont.offsetx = ACFONT_HEAD_OFFSETX(head); gblfont.offsetx = ACFONT_HEAD_OFFSETX(head);
gblfont.offsety = ACFONT_HEAD_OFFSETY(head); gblfont.offsety = ACFONT_HEAD_OFFSETY(head);
// get filesize // get filesize
gblfont.filesize = fSize(font); fseek(font, 0, SEEK_END);
gblfont.filesize = ftell(font);
if (gblfont.filename != NULL) if (gblfont.filename != NULL)
{
free(gblfont.filename); free(gblfont.filename);
if (gblfont.chapter != NULL) gblfont.filename = NULL;
free(gblfont.chapter); }
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 // get index chapters
// 1 decide chapter count // 1 decide chapter count
const int nparts = ACFONT_CHAPTER_MEMORY / ACFONT_SIZEOF_INDEX; uint16_t memfrag = ACFONT_HEAD_MEMFRAG(head);
int nchapter = gblfont.amount / nparts; uint8_t *fragments = (uint8_t*)malloc(memfrag);
if (nchapter * nparts < gblfont.amount) if( fragments == NULL )
{ {
++nchapter; fclose(font);
}
// 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);
return ACFONT_MEM_EMPTY; return ACFONT_MEM_EMPTY;
} }
// 3 load chapter to cache readed = fread(fragments, 1, memfrag, font);
for (int i = 0; i < nchapter; ++i) if( readed != memfrag )
{ {
int pos = ACFONT_INDEX(i * nparts); free( fragments );
if( RES_OK != fLseek(font, pos) ) fclose(font);
{ return ACFONT_INVALID;
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);
} }
gblfont.chapter = pchapter;
// save filename for `fopen` // save filename for `fopen`
int len = strlen(acfile); int len = strlen(acfile);
char *file = (char *)malloc(len + 1); char *file = (char *)malloc(len + 1);
if (file == NULL) if (file == NULL)
{ {
free(gblfont.chapter); free( fragments );
memset(&gblfont, 0, sizeof(gblfont)); memset(&gblfont, 0, sizeof(gblfont));
fClose(font); fclose(font);
return ACFONT_MEM_EMPTY; return ACFONT_MEM_EMPTY;
} }
@ -139,7 +138,10 @@ int acf_set_font(const char *acfile)
file[len] = 0; file[len] = 0;
gblfont.filename = file; gblfont.filename = file;
fClose(font); gblfont.fragments = (Fragment*)fragments;
gblfont.fragsize = memfrag;
fclose(font);
return 0; return 0;
} }
@ -188,86 +190,36 @@ static inline const char *next_unicode(const char *utf8, uint32_t *code)
return utf8; return utf8;
} }
static int bsearch_font(FHandle fd, uint32_t unicode) static int bsearch_font(FILE *fd, uint32_t unicode, Fragment **pFrag)
{ {
u32 readed; int retval = 0;
uint8_t *memory = (uint8_t*)gblfont.fragments;
// decide chapter count for( int i=0; i < gblfont.fragsize; )
const int nparts = ACFONT_CHAPTER_MEMORY / ACFONT_SIZEOF_INDEX;
int nchapter = gblfont.amount / nparts;
if (nchapter * nparts < gblfont.amount)
{ {
++nchapter; Fragment *frag = (Fragment*)&memory[i];
} if( frag->start <= unicode ) {
if( unicode <= frag->end )
int min = 0, max = nchapter; {
int m, found = 0; // hit
int diff = unicode - frag->start;
// search in chapter *pFrag = frag;
for (m = (min + max) >> 1; min < m; m = (min + max) >> 1) return retval + frag->padding * diff;
{ }
uint16_t code = gblfont.chapter[m]; else {
if (unicode < code) retval += frag->padding * (frag->end - frag->start + 1);
max = m; i += sizeof(Fragment) + ACFONT_SIZEOF_BBX * frag->bbxdcnt;
else if (code < unicode) }
min = m;
else
{
found = 1;
break;
} }
else return ACFONT_NOT_FOUND;
} }
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;
} }
#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 #define SIZEOF_S6 6
static inline int readS6(uint8_t *p, int index) 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; 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; uint32_t readed;
u16 color = consoleGetFgColor();
u16 *frame = consoleGetDefault()->frameBuffer;
// 获取code对应的字体信息 // 获取code对应的字体信息
int font_pos = bsearch_font(fd, code); Fragment *frag;
int font_pos = bsearch_font(fd, code, &frag);
if (font_pos < 0) if (font_pos < 0)
return 0; {
return -1;
}
font_pos += ACFONT_HEAD_SIZE + gblfont.fragsize;
if ((uint32_t)font_pos > gblfont.filesize) 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]; uint8_t font[ACFONT_SIZEOF_GLYPH], *glyph;
if( RES_OK != fLseek(fd, font_pos) ) if( 0 != fseek(fd, font_pos, SEEK_SET) )
return 1; return -3;
if( RES_OK != fRead(fd, font, ACFONT_SIZEOF_GLYPH, &readed) || readed = fread(font, 1, frag->padding, fd);
(readed != ACFONT_SIZEOF_GLYPH && (uint32_t)font_pos + ACFONT_SIZEOF_GLYPH < gblfont.filesize) ) if( readed != (uint32_t)frag->padding )
return 1; return -4;
int8_t bbx[4]; int8_t bbx[4], fw;
bbx[0] = readS6(font, 0); uint8_t *bbxd;
bbx[1] = readS6(font, SIZEOF_S6); if( frag->bbxdcnt == 1 )
bbx[2] = readS6(font, SIZEOF_S6 * 2); {
bbx[3] = readS6(font, SIZEOF_S6 * 3); bbxd = ACFONT_BBXD_FROM_FRAG(frag, 0);
int fw = readS6(font, SIZEOF_S6 * 4); 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 // render
// 从上往下(y从大到小x从小到大)进行绘制 // 从上往下(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计算位置进行绘制 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) 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; *x = px + fw;
*y = py;
return 0; return 0;
} }
// 根据字体绘制中文字符 // 根据字体绘制中文字符
// x,y - 绘制一行字符的基准点 // x,y - 绘制一行字符的基准点
// width - 最长绘制多少个像素点填0则忽略此参数 // maxwidth - 最长绘制多少个像素点填0则忽略此参数
// utf8_line - utf8字符串 // utf8_line - utf8字符串
// 返回第一个未绘制的字符的位置如果width为0则返回永远是NULL // 返回第一个未绘制的字符的位置如果width为0则返回永远是NULL
const char *acf_draw(int x, int y, unsigned width, unsigned height, unsigned maxwidth, const char *utf8_line) const char *acf_draw(int x, int y, unsigned width, unsigned height, unsigned maxwidth, const char *utf8_line)
{ {
u32 font; FILE *font;
if( gblfont.filename == NULL || RES_OK != fOpen(&font, gblfont.filename, FA_READ) ) int linex = 0;
if( gblfont.filename == NULL || (font = fopen(gblfont.filename, "rb")) == NULL )
{ {
// log // log
return utf8_line; return utf8_line;
} }
uint32_t unicode; uint32_t unicode;
if( maxwidth == 0 ) maxwidth = width;
unsigned *option = width == 0 ? NULL : &maxwidth; 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); for (const char *next = next_unicode(utf8_line, &unicode);
next != NULL; next != NULL;
next = next_unicode(utf8_line, &unicode)) 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) if (error)
{ {
fClose(font); free( localram );
fclose(font);
return utf8_line; return utf8_line;
} }
utf8_line = next; 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; return NULL;
} }