vxKernel/src/display/text/render/dtext.c

201 lines
4.2 KiB
C

#include <vhex/display/types.h>
#include <vhex/display/stack.h>
#include <vhex/display/font.h>
#include <vhex/display/text.h>
#include <vhex/display.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* internal text information/cache */
struct {
struct {
struct {
char *raw;
size_t size;
} *text;
int number;
int idx;
} pool;
} dtext_info = {
.pool = {
.text = NULL,
.number = 0,
.idx = 0
}
};
//---
// Internal module functions
//---
VCONSTRUCTOR static void __dtext_constructor(void)
{
dtext_info.pool.number = 16;
dtext_info.pool.idx = -1;
dtext_info.pool.text = calloc(
dtext_info.pool.number,
sizeof(*dtext_info.pool.text)
);
for (int i = 0; i < dtext_info.pool.number; ++i) {
dtext_info.pool.text[i].raw = malloc(32);
dtext_info.pool.text[i].size = 32;
}
}
VDESTRUCTOR void __dtext_destructor(void)
{
for (int i = 0; i < dtext_info.pool.number; ++i)
free(dtext_info.pool.text[i].raw);
free(dtext_info.pool.text);
}
static void __dtext_quit(void)
{
dtext_info.pool.idx = -1;
}
//---
// Private functions
//---
/* dtext_info_register() : duplicate the string */
static char *dtext_info_register(char const * const str)
{
size_t len;
dtext_info.pool.idx += 1;
if (dtext_info.pool.idx >= dtext_info.pool.number) {
dtext_info.pool.number += dtext_info.pool.number;
dtext_info.pool.text = reallocarray(
dtext_info.pool.text,
dtext_info.pool.number,
sizeof(*dtext_info.pool.text)
);
for (int i = dtext_info.pool.idx; i < dtext_info.pool.number; ++i) {
dtext_info.pool.text[i].raw = malloc(32);
dtext_info.pool.text[i].size = 32;
}
}
len = strlen(str) + 1;
if (len >= dtext_info.pool.text[dtext_info.pool.idx].size) {
dtext_info.pool.text[dtext_info.pool.idx].size = len;
dtext_info.pool.text[dtext_info.pool.idx].raw = reallocarray(
dtext_info.pool.text[dtext_info.pool.idx].raw,
dtext_info.pool.text[dtext_info.pool.idx].size,
sizeof(char)
);
}
strcpy(dtext_info.pool.text[dtext_info.pool.idx].raw, str);
return dtext_info.pool.text[dtext_info.pool.idx].raw;
}
//---
// Dstack API
//---
/* dfont_render() : draw caracter in surface */
void dtext_dstack(dsurface_t *surface, uintptr_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*)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
//---
/* dtext_opt(): Display a string of text */
did_t dtext_opt(
int x, int y,
int fg, int bg,
int align,
char const * const str, int size
) {
size_t width;
size_t height;
void *real_str;
/* get text geometry and handle obvious culling */
if (dtext_geometry(str, &size, &width, &height) != 0)
return (-1);
if (x >= (int)dwidth()
|| y >= (int)dheight()
|| x + (int)width < 0
|| y + (int)height < 0) {
return (-1);
}
/* handle position */
if (align & DTEXT_CENTER) x = x - (width / 2);
if (align & DTEXT_RIGHT) x = x - (width);
if (align & DTEXT_MIDDLE) y = y - (height / 2);
if (align & DTEXT_BOTTOM) y = y - (height);
/* register the string */
real_str = dtext_info_register(str);
/* request draw call */
return dstack_add_action(
DSTACK_CALL(
&dtext_dstack,
x, y, x + width, y + height,
fg, bg,
(uintptr_t)real_str, size,
),
NULL,
(dtext_info.pool.idx == 0) ? (void*)&__dtext_quit : NULL
);
}
/* dtext() : display text information */
did_t dtext(int x, int y, int fg, char const * const text)
{
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT | DTEXT_TOP, text, -1));
}