270 lines
5.6 KiB
C
270 lines
5.6 KiB
C
#include <vhex/display/font.h>
|
|
#include <vhex/display/draw/pixel.h>
|
|
#include <vhex/display/color.h>
|
|
|
|
//---
|
|
// Internal
|
|
//---
|
|
|
|
/* dfont_utf8_next(): Read the next UTF-8 code point of a string */
|
|
static uint32_t dfont_utf8_next(uint8_t const **str_pointer)
|
|
{
|
|
uint8_t const *str = *str_pointer;
|
|
uint8_t lead = *str++;
|
|
|
|
/* Skip non-leaders which are invalid as starting bytes */
|
|
while((lead >= 0x80 && lead <= 0xbf) ||
|
|
lead == 0xc0 || lead == 0xc1 || lead == 0xfe || lead == 0xff) {
|
|
lead = *str++;
|
|
}
|
|
|
|
/* This base case will handle the NUL terminator */
|
|
if(lead <= 0x7f) {
|
|
*str_pointer = str;
|
|
return lead;
|
|
}
|
|
|
|
uint8_t n2 = (*str++ & 0x3f);
|
|
if(lead <= 0xdf) {
|
|
*str_pointer = str;
|
|
return ((lead & 0x1f) << 6) | n2;
|
|
}
|
|
|
|
uint8_t n3 = (*str++ & 0x3f);
|
|
if(lead <= 0xef) {
|
|
*str_pointer = str;
|
|
return ((lead & 0x0f) << 12) | (n2 << 6) | n3;
|
|
}
|
|
|
|
uint8_t n4 = (*str++ & 0x3f);
|
|
if(lead <= 0xf7) {
|
|
*str_pointer = str;
|
|
return ((lead & 0x07) << 18) | (n2 << 12) | (n3 << 6) | n4;
|
|
}
|
|
|
|
/* It the string is too invalid, force a space and try to continue */
|
|
*str_pointer = str;
|
|
return 0x20;
|
|
}
|
|
|
|
#if 0
|
|
/* dfont_glyph_index(): Obtain the glyph index of a Unicode code point */
|
|
int dfont_glyph_index(font_t const *f, uint32_t code_point)
|
|
{
|
|
int glyph_start = 0;
|
|
|
|
for(int i = 0; i < f->block_count; i++) {
|
|
int diff = code_point - f->blocks[i].start;
|
|
if(diff >= 0 && diff < f->blocks[i].length) {
|
|
return glyph_start + diff;
|
|
}
|
|
|
|
glyph_start += f->blocks[i].length;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
/* dfont_glyph_index(): Obtain the glyph index of a Unicode code point */
|
|
//TODO: suport unicode block
|
|
int dfont_glyph_index(font_t const *f, uint32_t code_point)
|
|
{
|
|
code_point -= ' ';
|
|
if ((int)code_point < 0 || code_point >= f->glyph.count)
|
|
return (-1);
|
|
return code_point;
|
|
}
|
|
|
|
/* dfont_char_render() : */
|
|
void dfont_char_render(
|
|
struct dshader_surface *surface,
|
|
int glyph_idx,
|
|
uint32_t *arg
|
|
) {
|
|
uint32_t glyph_bitmap;
|
|
uint32_t glyph_shift;
|
|
int glyph_width;
|
|
int glyph_size;
|
|
font_t *font;
|
|
int counter;
|
|
int sx;
|
|
int x;
|
|
int y;
|
|
|
|
x = arg[0];
|
|
y = arg[1];
|
|
|
|
/* generate font index / shift information */
|
|
font = dfont_get();
|
|
if (font->shape.prop == 1) {
|
|
glyph_width = font->glyph.prop[glyph_idx].width;
|
|
glyph_shift = font->glyph.prop[glyph_idx].shift;
|
|
glyph_idx = font->glyph.prop[glyph_idx].index;
|
|
glyph_size = glyph_width * font->glyph.height;
|
|
} else {
|
|
glyph_width = font->glyph.mono.width;
|
|
glyph_size = font->glyph.mono.storage_size;
|
|
glyph_shift = glyph_size * glyph_idx;
|
|
glyph_idx = glyph_shift >> 8;
|
|
glyph_shift = glyph_shift & 0xff;
|
|
}
|
|
|
|
/* drawing algo */
|
|
//TODO: cache surface data (limit read/write)
|
|
sx = x;
|
|
counter = 0;
|
|
glyph_shift = 0x80000000 >> glyph_shift;
|
|
glyph_bitmap = font->glyph.data[glyph_idx];
|
|
for (int i = 0; i < glyph_size; ++i)
|
|
{
|
|
if (glyph_bitmap & glyph_shift) {
|
|
dpixel_render(surface, x, y, arg[4]);
|
|
} else {
|
|
dpixel_render(surface, x, y, arg[5]);
|
|
}
|
|
|
|
/* update font bitmap index / shift */
|
|
glyph_shift >>= 1;
|
|
if (glyph_shift == 0x00000000) {
|
|
glyph_shift = 0x80000000;
|
|
glyph_bitmap = font->glyph.data[++glyph_idx];
|
|
}
|
|
|
|
/* update bitmap position */
|
|
x += 1;
|
|
counter += 1;
|
|
if (counter >= glyph_width) {
|
|
counter = 0;
|
|
x = sx;
|
|
y += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---
|
|
// Kernel-level API
|
|
//---
|
|
|
|
/* dfont_render() : draw caracter in surface */
|
|
void dfont_text_render(struct dshader_surface *surface, uint32_t *arg)
|
|
{
|
|
uint32_t code_point;
|
|
uint8_t const * str;
|
|
font_t *font;
|
|
int glyph_idx;
|
|
int glyph_width;
|
|
int counter;
|
|
int sx;
|
|
int sy;
|
|
|
|
/* check culling */
|
|
if (((int)arg[3] < surface->y1 && (int)arg[1] > surface->y2)
|
|
|| ((int)arg[2] < surface->x1 && (int)arg[0] > surface->x2)) {
|
|
return;
|
|
}
|
|
|
|
/* draw algo (update me) */
|
|
sx = arg[0];
|
|
sy = arg[1];
|
|
counter = -1;
|
|
font = dfont_get();
|
|
str = (void*)(uintptr_t)arg[6];
|
|
while (++counter < (int)arg[7])
|
|
{
|
|
code_point = dfont_utf8_next(&str);
|
|
if (code_point == '\n') {
|
|
arg[1] += font->glyph.height;
|
|
arg[0] = sx;
|
|
continue;
|
|
}
|
|
|
|
glyph_idx = dfont_glyph_index(font, code_point);
|
|
glyph_width = font->glyph.mono.width;
|
|
if (font->shape.prop == 1)
|
|
glyph_width = font->glyph.prop[glyph_idx].width;
|
|
|
|
dfont_char_render(surface, glyph_idx, arg);
|
|
|
|
arg[0] += glyph_width + font->char_spacing;
|
|
|
|
}
|
|
arg[1] = sy;
|
|
arg[0] = sx;
|
|
}
|
|
|
|
//---
|
|
// Public API
|
|
//---
|
|
|
|
|
|
/* dfont_get() : get the current font */
|
|
font_t *dfont_get(void)
|
|
{
|
|
extern font_t font8x9;
|
|
return &font8x9;
|
|
}
|
|
|
|
/* dfont_geometry() : get the char geometry */
|
|
int dfont_text_geometry(
|
|
font_t *font,
|
|
char const * const str_char,
|
|
int *size,
|
|
size_t *w,
|
|
size_t *h
|
|
) {
|
|
uint8_t const *str0 = (void *)str_char;
|
|
uint8_t const *str1 = (void *)str_char;
|
|
uint32_t code_point;
|
|
size_t length = 0;
|
|
size_t mx = 0;
|
|
size_t x = 0;
|
|
size_t y = 0;
|
|
size_t glyph_width;
|
|
int glyph_idx;
|
|
int limit;
|
|
|
|
/* handle special behaviour */
|
|
if (font == NULL)
|
|
font = dfont_get();
|
|
limit = -1;
|
|
if (size != NULL && *size >= 0)
|
|
limit = *size;
|
|
|
|
/* generate geometry information */
|
|
while (1) {
|
|
code_point = dfont_utf8_next(&str0);
|
|
if (code_point == 0 || (limit > 0 && str0 - str1 >= limit))
|
|
break;
|
|
|
|
/* line discipline */
|
|
length++;
|
|
if (code_point == '\n') {
|
|
y += font->glyph.height;
|
|
x = 0;
|
|
continue;
|
|
}
|
|
|
|
glyph_width = font->glyph.mono.width;
|
|
if (font->shape.prop == 1) {
|
|
glyph_idx = dfont_glyph_index(font, code_point);
|
|
if (glyph_idx < 0) {
|
|
if (w != NULL) *w = 0;
|
|
if (h != NULL) *h = 0;
|
|
if (size != NULL) *size = length;
|
|
return (-1);
|
|
}
|
|
glyph_width = font->glyph.prop[glyph_idx].width;
|
|
}
|
|
|
|
x += glyph_width + font->char_spacing;
|
|
if (x > mx) mx = x;
|
|
}
|
|
|
|
/* set geometry information */
|
|
if (w != NULL) *w = mx - font->char_spacing;
|
|
if (h != NULL) *h = y;
|
|
if (size != NULL) *size = length;
|
|
return (0);
|
|
}
|