posix-uefi/examples/0A_bmpfont/bmpfont.c
2021-02-17 22:16:28 +01:00

120 lines
4 KiB
C

#include <uefi.h>
/* Scalable Screen Font (https://gitlab.com/bztsrc/scalable-font2) */
typedef struct {
unsigned char magic[4];
unsigned int size;
unsigned char type;
unsigned char features;
unsigned char width;
unsigned char height;
unsigned char baseline;
unsigned char underline;
unsigned short fragments_offs;
unsigned int characters_offs;
unsigned int ligature_offs;
unsigned int kerning_offs;
unsigned int cmap_offs;
} __attribute__((packed)) ssfn_font_t;
/* framebuffer properties */
unsigned int width, height, pitch;
unsigned char *lfb;
/* font to be used */
ssfn_font_t *font;
/**
* Display string using a bitmap font without the SSFN library
*/
void printString(int x, int y, char *s)
{
unsigned char *ptr, *chr, *frg;
unsigned int c;
uintptr_t o, p;
int i, j, k, l, m, n;
while(*s) {
c = 0; s += mbtowc((wchar_t*)&c, (const char*)s, 4);
if(c == '\r') { x = 0; continue; } else
if(c == '\n') { x = 0; y += font->height; continue; }
for(ptr = (unsigned char*)font + font->characters_offs, chr = 0, i = 0; i < 0x110000; i++) {
if(ptr[0] == 0xFF) { i += 65535; ptr++; }
else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; }
else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; }
else { if((unsigned int)i == c) { chr = ptr; break; } ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); }
}
if(!chr) continue;
ptr = chr + 6; o = (uintptr_t)lfb + y * pitch + x * 4;
for(i = n = 0; i < chr[1]; i++, ptr += chr[0] & 0x40 ? 6 : 5) {
if(ptr[0] == 255 && ptr[1] == 255) continue;
frg = (unsigned char*)font + (chr[0] & 0x40 ? ((ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]) :
((ptr[4] << 16) | (ptr[3] << 8) | ptr[2]));
if((frg[0] & 0xE0) != 0x80) continue;
o += (int)(ptr[1] - n) * pitch; n = ptr[1];
k = ((frg[0] & 0x1F) + 1) << 3; j = frg[1] + 1; frg += 2;
for(m = 1; j; j--, n++, o += pitch)
for(p = o, l = 0; l < k; l++, p += 4, m <<= 1) {
if(m > 0x80) { frg++; m = 1; }
if(*frg & m) *((unsigned int*)p) = 0xFFFFFF;
}
}
x += chr[4]+1; y += chr[5];
}
}
/**
* Display bitmap fonts
*/
int main(int argc, char **argv)
{
efi_status_t status;
efi_guid_t gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
efi_gop_t *gop = NULL;
efi_gop_mode_info_t *info = NULL;
uintn_t isiz = sizeof(efi_gop_mode_info_t);
FILE *f;
long int size;
/* load font */
if((f = fopen("\\0A_bmpfont\\font.sfn", "r"))) {
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
font = (ssfn_font_t*)malloc(size + 1);
if(!font) {
fprintf(stderr, "unable to allocate memory\n");
return 1;
}
fread(font, size, 1, f);
fclose(f);
} else {
fprintf(stderr, "Unable to load font\n");
return 0;
}
/* set video mode */
status = BS->LocateProtocol(&gopGuid, NULL, (void**)&gop);
if(!EFI_ERROR(status) && gop) {
status = gop->SetMode(gop, 0);
ST->ConOut->Reset(ST->ConOut, 0);
ST->StdErr->Reset(ST->StdErr, 0);
if(EFI_ERROR(status)) {
fprintf(stderr, "unable to set video mode\n");
return 0;
}
/* set up destination buffer */
lfb = (unsigned char*)gop->Mode->FrameBufferBase;
width = gop->Mode->Information->HorizontalResolution;
height = gop->Mode->Information->VerticalResolution;
pitch = sizeof(unsigned int) * gop->Mode->Information->PixelsPerScanLine;
} else {
fprintf(stderr, "unable to get graphics output protocol\n");
return 0;
}
/* display multilingual text */
printString(10, 10, "Hello 多种语言 Многоязычный többnyelvű World!");
/* free resources exit */
free(font);
return 0;
}