flipper_cyrillic_example/font/bdfconv/fd.c
2023-05-02 21:01:20 +03:00

227 lines
4.2 KiB
C

/*
fd.c
font decode
(obsolete? does not support unicode)
*/
#include "fd.h"
#include <stddef.h>
void fd_init(fd_t *fd)
{
fd->is_transparent = 1;
}
void fd_set_font(fd_t *fd, uint8_t *font)
{
fd->glyph_cnt = *font++;
font++; /* bbx mode */
fd->bits_per_0 = *font++;
fd->bits_per_1 = *font++;
fd->bits_per_char_width = *font++;
fd->bits_per_char_height = *font++;
fd->bits_per_char_x = *font++;
fd->bits_per_char_y = *font++;
fd->bits_per_delta_x = *font++;
fd->char_width = *font++;
fd->char_height = *font++;
font++; /* x offset */
fd->char_descent = *(int8_t *)font;
font++;
font++;
font++;
font++;
font++;
fd->capital_a_pos= *font++;
fd->capital_a_pos <<= 8;
fd->capital_a_pos |= *font++;
fd->small_a_pos = *font++;
fd->small_a_pos <<= 8;
fd->small_a_pos |= *font++;
/* TODO: proper unicode update */
font++;
font++;
fd->font = font;
}
uint8_t *fd_get_glyph_data(fd_t *fd, uint8_t encoding)
{
uint8_t *font = fd->font;
if ( encoding >= 'a' ) /* assumes 'a' > 'A' */
{
font += fd->small_a_pos;
}
else if ( encoding >= 'A' )
{
font += fd->capital_a_pos;
}
for(;;)
{
if ( font[1] == 0 )
break;
if ( font[0] == encoding )
{
return font;
}
font += font[1];
}
return NULL;
}
__attribute__((noinline)) unsigned fd_get_unsigned_bits(fd_t *f, unsigned cnt)
{
unsigned val;
unsigned bit_pos = f->decode_bit_pos;
unsigned rem_bits;
val = f->decode_byte;
rem_bits = 8;
rem_bits -= bit_pos;
bit_pos += cnt;
if ( cnt >= rem_bits )
{
f->decode_ptr++;
f->decode_byte = *(f->decode_ptr);
val |= f->decode_byte << (rem_bits);
bit_pos -= 8;
f->decode_byte >>= bit_pos;
}
else
{
f->decode_byte >>= cnt;
}
val &= (1U<<cnt)-1;
f->decode_bit_pos = bit_pos;
return val;
}
int fd_get_signed_bits(fd_t *fd, int cnt)
{
return (int)fd_get_unsigned_bits(fd, cnt) - ((1<<cnt)>>1);
}
void tga_draw_hline(unsigned x,unsigned y, unsigned cnt, unsigned is_foreground);
void fd_draw_pixel(fd_t *f, unsigned cnt, unsigned is_foreground)
{
if ( f->is_transparent != 0 && is_foreground == 0 )
return;
tga_draw_hline(f->target_x+f->x, f->target_y+f->y, cnt, is_foreground);
}
void fd_decode_len(fd_t *fd, unsigned len, unsigned is_foreground)
{
unsigned cnt, rem;
cnt = len;
for(;;)
{
rem = fd->glyph_width;
rem -= fd->x;
if ( cnt < rem )
break;
fd_draw_pixel(fd,rem, is_foreground);
cnt -= rem;
fd->x = 0;
fd->y++;
}
fd_draw_pixel(fd, cnt, is_foreground);
fd->x += cnt;
}
/*
expects:
unsigned target_x;
unsigned target_y;
unsigned is_transparent;
const uint8_t *decode_ptr;
*/
unsigned fd_decode(fd_t *f)
{
unsigned a, b;
int x, y;
unsigned d = 0;
f->decode_bit_pos = 0;
f->decode_ptr += 1;
f->decode_ptr += 1;
f->decode_byte = *(f->decode_ptr); /* init decoder */
f->glyph_width = fd_get_unsigned_bits(f, f->bits_per_char_width);
f->glyph_height = fd_get_unsigned_bits(f, f->bits_per_char_height);
x = fd_get_signed_bits(f, f->bits_per_char_x);
y = fd_get_signed_bits(f, f->bits_per_char_y);
d = fd_get_signed_bits(f, f->bits_per_delta_x);
if ( f->glyph_width > 0 )
{
f->target_x += x;
f->target_y -= f->glyph_height ;
f->target_y -=y ;
f->x = 0;
f->y = 0;
for(;;)
{
a = fd_get_unsigned_bits(f, f->bits_per_0);
b = fd_get_unsigned_bits(f, f->bits_per_1);
do
{
fd_decode_len(f, a, 0);
fd_decode_len(f, b, 1);
} while( fd_get_unsigned_bits(f, 1) != 0 );
if ( f->y >= f->glyph_height )
break;
}
}
return d;
}
unsigned fd_draw_glyph(fd_t *fd, unsigned x, unsigned y, uint8_t encoding)
{
unsigned dx = 0;
fd->target_x = x;
fd->target_y = y;
fd->decode_ptr = fd_get_glyph_data(fd, encoding);
if ( fd->decode_ptr != NULL )
{
dx = fd_decode(fd);
}
return dx;
}
unsigned fd_draw_string(fd_t *fd, unsigned x, unsigned y, const char *s)
{
unsigned dx = 0;
while( *s != '\0' )
{
dx += fd_draw_glyph(fd, x+dx,y,*s);
s++;
}
return dx;
}