94 lines
2.9 KiB
C
94 lines
2.9 KiB
C
#include "duet.h"
|
|
|
|
extern font_t font_duet;
|
|
|
|
/* topti functions exposed to each implementation */
|
|
int topti_glyph_index(font_t const *f, uint32_t code_point);
|
|
int topti_offset(font_t const *f, uint glyph);
|
|
uint32_t topti_utf8_next(uint8_t const **str_pointer);
|
|
|
|
/* topti_glyph(): Render a glyph on the VRAM
|
|
Prints a glyph naively using word accesses, because for most fonts with a
|
|
small size (including gint's 8x9 font) this will be more efficient than the
|
|
complex logic for longword accesses.
|
|
|
|
This function assumes that at least one of [fg] and [bg] is not transparent.
|
|
|
|
@x0 @y0 Target position on VRAM
|
|
@data Glyph data
|
|
@width Subglyph width
|
|
@height Subglyph height
|
|
@fg @bg Foreground and background colors */
|
|
static void topti_glyph(int x0, int y0, uint32_t const * data, int width,
|
|
int height, int fg, int bg)
|
|
{
|
|
/* A C version of what is usually done in assembler */
|
|
for(int y = 0; y < height; y++) {
|
|
for(int x = 0; x < width; x++) {
|
|
int bit_number = y * width + x;
|
|
int bit = (data[bit_number >> 5] >> (31 - (bit_number & 31))) & 1;
|
|
|
|
/* Swithing x->height-y-1 and y->x here gives vertical glyphs */
|
|
if((bit ? fg : bg) != C_NONE)
|
|
dpixel(x0 + (height-y-1), y0 + x, bit ? fg : bg);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void topti_render(int x, int y, char const *str_char, font_t const *f,
|
|
int fg, int bg, int size)
|
|
{
|
|
uint8_t const *str = (void *)str_char;
|
|
uint8_t const *str0 = str;
|
|
|
|
/* Raw glyph data */
|
|
uint32_t const *data = f->data;
|
|
|
|
/* Character spacing waiting to be drawn, in pixels */
|
|
int space = 0;
|
|
|
|
/* Read each character from the input string */
|
|
while(1)
|
|
{
|
|
uint32_t code_point = topti_utf8_next(&str);
|
|
if(!code_point || (size >= 0 && str - str0 > size)) break;
|
|
|
|
int glyph = topti_glyph_index(f, code_point);
|
|
if(glyph < 0) continue;
|
|
|
|
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
|
|
|
|
/* Draw character spacing if background is opaque */
|
|
if(space && bg >= 0) drect(x, y, x+f->data_height-1, y+space-1, bg);
|
|
y += space;
|
|
if(y >= DHEIGHT) break;
|
|
|
|
int index = topti_offset(f, glyph);
|
|
|
|
/* Render glyph */
|
|
topti_glyph(x, y, data + index, dataw, f->data_height, fg, bg);
|
|
|
|
/* Switching x -> y here (and some other places, but mostly here) gives
|
|
vertical text */
|
|
y += dataw;
|
|
space = f->char_spacing;
|
|
}
|
|
}
|
|
|
|
void duet_text_opt(int x, int y, int fg, int bg, int halign, int valign,
|
|
char const *str, int size)
|
|
{
|
|
if(halign != DTEXT_LEFT || valign != DTEXT_TOP)
|
|
{
|
|
int w, h;
|
|
dnsize(str, size, &font_duet, &w, &h);
|
|
|
|
if(halign == DTEXT_RIGHT) x -= h - 1;
|
|
if(halign == DTEXT_CENTER) x -= (h >> 1);
|
|
if(valign == DTEXT_BOTTOM) y -= w - 1;
|
|
if(valign == DTEXT_MIDDLE) y -= (w >> 1);
|
|
}
|
|
|
|
topti_render(x, y, str, &font_duet, fg, bg, size);
|
|
}
|