VxKernel 0.6.0-2 : Prepare font and text API (WIP)

@add
<> include/vhex/display :
   | add dwidth() primitive
   | add dheight() primitive
<> include/vhex/display/font :
   | create a font structure that support proportional font
   | expose font primitives API (WIP)
<> vhex/module/display/text/dfont:
   | support utf8 string format
   | add geometry font information (WIP)
<> vhex/module/display/text/dtext:
   | write most of the API primitive (WIP)
   | proper isolation between font <-> text API

@update
<> include/vhex/display/shader :
   | add a quit() routine that will be involved at the end of dupdate()
   | add display_[width/height] in driver interface
   | add display screen information primitives
<> vhex/drivers/screen/r61524/r61524.c
   | add display driver interface screen information
<> vhex/module/display/dclear:
   | use the 32-bits arguments instead of the broken dshader_call_arg_t
   | support the new API with quit() routine
<> vhex/module/display/dstack:
   | support the new display screen information
   | support the quit() routine at the end of the dupdate()

@fix
<> include/vhex/display/shader :
   | remove broken transparent-union implicit cast
   | fix argument transmitted to drawing routine (only 32bit arguments supported)
This commit is contained in:
Yann MAGNIN 2022-05-28 21:55:48 +02:00
parent a916120d66
commit 510c4f1f86
10 changed files with 475 additions and 139 deletions

View File

@ -5,8 +5,9 @@
#include <vhex/display/types.h>
#include <vhex/display/draw.h>
#include <vhex/display/color.h>
#include <vhex/display/text.h>
//#include <vhex/display/image.h>
//#include <vhex/display/text.h>
#include <vhex/display/stack.h>
//TODO: doc
@ -17,12 +18,16 @@ extern did_t dclear(int color);
extern void dupdate(void);
/* dwidth(): get the screen width */
extern size_t dwidth(void);
VINLINE size_t dwidth(void)
{
return dstack_display_width();
}
/* dheight(): get the heigth of the screen */
extern size_t dheight(void);
VINLINE size_t dheight(void)
{
return dstack_display_height();
}
@ -33,29 +38,6 @@ extern size_t dheight(void);
// Text render API
//---
#if 0
/* Alignment settings for dtext_opt() and dprint_opt(). Combining a vertical
and a horizontal alignment option specifies where a given point (x,y) should
be relative to the rendered string. */
enum {
/* Horizontal settings: default in dtext() is DTEXT_LEFT */
DTEXT_LEFT = 0,
DTEXT_CENTER = 1,
DTEXT_RIGHT = 2,
/* Vertical settings: default in dtext() is DTEXT_TOP */
DTEXT_TOP = 0,
DTEXT_MIDDLE = 1,
DTEXT_BOTTOM = 2,
};
/* dtext_opt(): Display a string of text */
extern void dtext_opt(
int x, int y,
int fg, int bg,
int halign, int valign,
char const *str, int size
);
@ -70,17 +52,9 @@ extern void dascii(int x, int y, int fg, int bg, int n);
/* dline(): Render a straight line */
extern void dline(int x1, int y1, int x2, int y2, int color);
/* dtext() : display raw text */
extern void dtext(int x, int y, int fg, char const * restrict const text);
/* dprint() : display formated text */
extern void dprint(int x, int y, int fg, char const * const text, ...);
/* dsize(): Get the width and height of rendered text */
extern void dsize(char const *str, int *w, int *h);
/* dnsize(): Get the width and height of rendered text for the n first char */
extern void dnsize(char const *str, int n, int *w, int *h);
/* drect(): Fill a rectangle of the screen */
extern void drect(int x1, int y1, int x2, int y2, int color);

View File

@ -0,0 +1,85 @@
#ifndef __VHEX_DISPLAY_FONT__
# define __VHEX_DISPLAY_FONT__
#include <vhex/defs/types.h>
#include <vhex/defs/attributes.h>
#include <vhex/display/shader.h>
/* font_t: Font data encoded for dfont*() functions */
typedef struct font {
/* Font name (NUL-terminated), NULL if no title */
char const *name;
/* Font shape flags */
byte_union(shape,
uint8_t bold :1;
uint8_t italic :1;
uint8_t serif :1;
uint8_t mono :1;
uint8_t :3;
uint8_t prop :1;
);
/* Line height */
uint8_t line_height;
/* Storage height */
uint8_t data_height;
/* Number of Unicode blocks */
uint8_t block_count;
/* Number of total glyphs */
uint32_t glyph_count;
/* Character spacing (usually 1) */
uint8_t char_spacing;
struct {
/* Unicode point of first character in block */
uint32_t start :20;
/* Length of block */
uint32_t length :12;
} *blocks;
/* Raw glyph data */
uint32_t *data;
union {
/* For monospaced fonts */
struct {
/* Width of glyphs */
uint16_t width;
/* Storage size, in longwords, of each glyph */
uint16_t storage_size;
};
/* For proportional fonts */
struct {
/* Storage index to find glyphs quickly */
uint16_t *glyph_index;
/* Width of each individual glyph */
uint8_t *glyph_width;
};
};
} VPACKED(4) font_t;
/* dfont_get() : get the current font */
extern font_t *dfont_get(void);
/* dfont_text_geometry() : get the char geometry */
extern int dfont_text_geometry(
font_t *font,
char const * const str_char,
int *size,
size_t *w,
size_t *h
);
//---
// Kernel-level API
//---
/* dfont_render() : draw caracter in surface */
extern void dfont_text_render(struct dshader_surface *surface, uint32_t *arg);
#endif /* __VHEX_DISPLAY_FONT__ */

View File

@ -4,58 +4,6 @@
#include <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
/* dshader_call_arg_t: All types of arguments allowed in an indirect shader call
Because a function call cannot be easily pieced together, there are
restrictions on what arguments can be passed. The following union lists all
of the available types. Other types can be used if casted, mainly pointers;
see the description of DSHADER*() for details. */
typedef union dshader_call_arg {
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
/* 32-bit integers */
int i;
unsigned int u;
int32_t i32;
uint32_t u32;
/* 32-bit floating-point */
float f;
/* Pointers to most common types, in all possible const/volatile
qualifications */
#define POINTER(type, name) \
type *name; \
type const *name ## _c; \
type volatile *name ## _v; \
type volatile const *name ## _cv;
POINTER(void, pv)
POINTER(char, pc)
POINTER(unsigned char, puc)
POINTER(short, ps)
POINTER(unsigned short, pus)
POINTER(int, pi)
POINTER(unsigned int, pui)
POINTER(int8_t, pi8)
POINTER(uint8_t, pu8)
POINTER(int16_t, pi16)
POINTER(uint16_t, pu16)
POINTER(int32_t, pi32)
POINTER(uint32_t, pu32)
POINTER(int64_t, pi64)
POINTER(uint64_t, pu64)
POINTER(long long int, pll)
POINTER(unsigned long long int, pull)
POINTER(float, pf)
POINTER(double, pd)
#undef POINTER
} dshader_call_arg_t;
/* dshader_surface - Describe the surface */
struct dshader_surface {
void *draw;
@ -70,10 +18,10 @@ struct dshader_surface {
struct dshader_call {
int (*routine)(
struct dshader_surface *surface,
dshader_call_arg_t *draw_args,
dshader_call_arg_t *shader_args
uint32_t *draw_args,
uint32_t *shader_args
);
dshader_call_arg_t args[8];
uint32_t args[8];
};
typedef struct dshader_call dshader_call_t;
typedef struct dshader_call dshader_t;

View File

@ -6,11 +6,11 @@
/* dstack_call - dstack indirect call (same as dshader) */
struct dstack_call {
int (*routine)(
void (*routine)(
struct dshader_surface *surface,
dshader_call_arg_t *draw_args
uint32_t *draw_args
);
dshader_call_arg_t args[12];
uint32_t args[12];
};
typedef struct dstack_call dstack_call_t;
@ -22,13 +22,12 @@ struct dstack_action {
int number;
int idx;
} shader;
void (*quit)(uint32_t *arg);
};
/* DSTACK_CALL - display indirect call */
#pragma GCC diagnostic ignored "-Wmissing-braces"
#define DSTACK_CALL(fct, ...) (dstack_call_t){ \
.routine = (void*)fct, \
.routine = fct, \
.args = { __VA_ARGS__ } \
}
@ -58,6 +57,8 @@ struct dstack_drv_interface {
int (*frame_frag_next)(struct dshader_surface *);
int (*frame_frag_send)(struct dshader_surface *);
int (*frame_end)(struct dshader_surface *);
size_t display_width;
size_t display_height;
};
//---
@ -68,7 +69,11 @@ struct dstack_drv_interface {
extern int dstack_init(struct dstack_config *config);
/* dstack_add_action() : add a new action in the draw stack */
extern did_t dstack_add_action(dstack_call_t *call, dshader_call_t *shaders);
extern did_t dstack_add_action(
dstack_call_t *call,
dshader_call_t *shaders,
void (*quit)(uint32_t *args)
);
/* dstack_get_action() : get display stack action using its ID */
extern struct dstack_action *dstack_get_action(did_t did);
@ -79,9 +84,14 @@ extern void dstack_render(void);
/* dstack_invalidate() : Invalidate the draw stack (reset) */
extern int dstack_invalidate(void);
/* dstack_display_width() : return the display width */
extern size_t dstack_display_width(void);
/* dstack_display_height() : return the display height */
extern size_t dstack_display_height(void);
/* dstack_quit() : Uninit the draw stack */
extern int dstack_quit(void);
#endif /* __VHEX_DISPLAY_STACK__ */

View File

@ -0,0 +1,46 @@
#ifndef __VHEX_DISPLAY_TEXT__
# define __VHEX_DISPLAY_TEXT__
#include <vhex/defs/types.h>
#include <vhex/display/types.h>
/* Alignment settings for dtext_opt() and dprint_opt(). Combining a vertical
and a horizontal alignment option specifies where a given point (x,y) should
be relative to the rendered string. */
enum {
/* Horizontal settings: default in dtext() is DTEXT_LEFT */
DTEXT_LEFT = 0,
DTEXT_CENTER = 1,
DTEXT_RIGHT = 2,
/* Vertical settings: default in dtext() is DTEXT_TOP */
DTEXT_TOP = 0,
DTEXT_MIDDLE = 1,
DTEXT_BOTTOM = 2,
};
/* dtext_opt(): Display a string of text */
extern did_t dtext_opt(
int x, int y,
int fg, int bg,
int halign, int valign,
char const * const str, int size
);
/* dtext() : display raw text */
extern did_t dtext(int x, int y, int fg, char const * const text);
/* dprint_opt(): Display a formated string */
extern did_t dprint_opt(
int x, int y,
int fg, int bg,
int halign, int valign,
char const * const str, ...
);
/* dprint() : display formated text */
extern did_t dprint(int x, int y, int fg, char const * const text, ...);
/* dnsize(): Get the width and height of rendered text for the n first char */
extern int dtext_geometry(char const * const str, int *n, size_t *w, size_t *h);
#endif /* __VHEX_DISPLAY_TEXT__ */

View File

@ -148,7 +148,9 @@ static struct dstack_drv_interface drv_r61524_dstack = {
.frame_start = &r61524_frame_start,
.frame_frag_next = &r61524_frame_frag_next,
.frame_frag_send = &r61524_frame_frag_send,
.frame_end = &r61524_frame_end
.frame_end = &r61524_frame_end,
.display_width = 396,
.display_height = 224
};
struct vhex_driver drv_r61524 = {

View File

@ -3,16 +3,13 @@
#include <vhex/display/stack.h>
/* dclear_draw() : real drawing algorithm */
static void dclear_draw(
struct dshader_surface *surface,
dshader_call_arg_t *arg
)
static void dclear_draw(struct dshader_surface *surface, uint32_t *arg)
{
uint32_t * restrict vram;
uint32_t color;
vram = surface->frag;
color = arg[0].u16 & 0xffff;
color = arg[0] & 0xffff;
for (int i = 0; i < 2048; ++i)
vram[i] = (color << 16) | (color << 0);
}
@ -20,5 +17,5 @@ static void dclear_draw(
/* dclear(): Fill the screen with a single color */
did_t dclear(int color)
{
return dstack_add_action(&DSTACK_CALL(&dclear_draw, color), NULL);
return dstack_add_action(&DSTACK_CALL(&dclear_draw, color), NULL, NULL);
}

View File

@ -23,6 +23,8 @@ static struct {
.frame_frag_next = NULL,
.frame_frag_send = NULL,
.frame_end = NULL,
.display_width = 0,
.display_height = 0
}
};
@ -77,8 +79,11 @@ int dstack_quit(void)
// Internal API
//
static did_t dstack_action_alloc(dstack_call_t *call, dshader_call_t *shader)
{
static did_t dstack_action_alloc(
dstack_call_t *call,
dshader_call_t *shader,
void (*quit)(uint32_t *arg)
) {
struct dstack_action *action;
int i;
@ -106,20 +111,24 @@ static did_t dstack_action_alloc(dstack_call_t *call, dshader_call_t *shader)
&shader[i],
sizeof(dshader_call_t)
);
action->quit = quit;
}
}
action->shader.idx = i;
return dstack_info.pool.idx;
}
//
//---
// Public API
//
//---
/* dstack_add_action() : add a new action in the draw stack */
did_t dstack_add_action(dstack_call_t *call, dshader_call_t *shader)
{
return dstack_action_alloc(call, shader);
did_t dstack_add_action(
dstack_call_t *call,
dshader_call_t *shader,
void (*quit)(uint32_t *arg)
) {
return dstack_action_alloc(call, shader, quit);
}
/* dstack_render(): render a frame */
@ -129,6 +138,7 @@ void dstack_render(void)
struct dstack_action *action;
action = dstack_info.pool.action;
dstack_info.driver.frame_start(&surface);
do {
for (int i = 0; i <= dstack_info.pool.idx; ++i) {
@ -144,5 +154,23 @@ void dstack_render(void)
dstack_info.driver.frame_frag_send(&surface);
} while (dstack_info.driver.frame_frag_next(&surface) == 0);
dstack_info.driver.frame_end(&surface);
for (int i = 0; i <= dstack_info.pool.idx; ++i) {
if (action[i].quit != NULL)
action[i].quit(action[i].call.args);
}
dstack_info.pool.idx = 0;
}
/* dstack_display_width() : return the display width */
extern size_t dstack_display_width(void)
{
return dstack_info.driver.display_width;
}
/* dstack_display_height() : return the display height */
extern size_t dstack_display_height(void)
{
return dstack_info.driver.display_height;
}

View File

@ -0,0 +1,134 @@
#include <vhex/display/font.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;
}
/* 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;
}
//---
// 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 char_width;
size_t length = 0;
size_t mx = 0;
size_t x = 0;
size_t y = 0;
int limit;
int glyph;
/* 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;
char_width = font->width;
if (font->shape.prop == 1) {
glyph = dfont_glyph_index(font, code_point);
if (glyph < 0)
return (-1);
char_width = font->glyph_width[glyph];
}
/* line discipline */
x += char_width;
if (code_point == '\n') {
y += font->data_height;
x = 0;
}
if (x > mx) mx = x;
length++;
}
/* set geometry information */
if (w != NULL) *w = mx;
if (h != NULL) *h = y;
if (size != NULL) *size = length;
return (0);
}

View File

@ -1,51 +1,147 @@
#if 0
#include "vhex/display.h"
#include "vhex/defs/types.h"
#include <vhex/defs/types.h>
#include <vhex/display/text.h>
#include <vhex/display/shader.h>
#include <vhex/display/stack.h>
#include <vhex/display/color.h>
#include <vhex/display/font.h>
#include <vhex/display.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
//TODO: dynamic
extern struct {
uint32_t width;
uint32_t height;
uint32_t pixel[];
} font8x9;
struct dtext_geometry {
struct {
char *raw;
size_t raw_size;
int size;
} text;
int x;
int y;
};
static struct {
struct {
struct dtext_geometry *geometry;
int number;
int idx;
} pool;
} dtext_info = {
.pool = {
.geometry = 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.geometry = calloc(
dtext_info.pool.number,
sizeof(struct dtext_geometry)
);
for (int i = 0; i < dtext_info.pool.number; ++i) {
dtext_info.pool.geometry[i].text.raw = malloc(32);
dtext_info.pool.geometry[i].text.raw_size = 32;
dtext_info.pool.geometry[i].text.size = 0;
}
}
VDESTRUCTOR void __dtext_destructor(void)
{
for (int i = 0; i < dtext_info.pool.number; ++i)
free(dtext_info.pool.geometry[i].text.raw);
free(dtext_info.pool.geometry);
}
static void __dtext_quit(void)
{
dtext_info.pool.idx = 0;
}
//---
// Drawing functions
//---
#if 0
static void dtext_opt_draw(struct dshader_surface *surface, uint32_t *arg)
{
uint32_t buff[5];
char *str;
buff[0] = (uintptr_t)dfont_get();
buff[1] = arg[0]; // x
buff[2] = arg[1]; // y
buff[3] = arg[2]; // fg
buff[4] = arg[3]; // bg
str = (void*)(uintptr_t)arg[4];
for (int i = 0; i < (int)arg[5]; ++i) {
buff[5] = str[i];
dfont_render(surface, buff);
}
}
#endif
//---
// Public API
//---
/* dtext_opt(): Display a string of text */
void dtext_opt(
did_t dtext_opt(
int x, int y,
int fg, int bg,
int halign, int valign,
char const *str, int size
char const * const str, int size
) {
int height;
int width;
size_t width;
size_t height;
if (size < 0)
size = 65535;
/* get text geometry and handle obvious culling */
if (dfont_text_geometry(NULL, str, &size, &width, &height) != 0)
return (-1);
if (x >= (int)dwidth()
|| y >= (int)dheight()
|| x + (int)width < 0
|| y + (int)height < 0) {
return (-1);
}
dnsize(str, size, &width, &height);
/* handle position */
if (halign == DTEXT_CENTER) x = x - (width / 2);
if (halign == DTEXT_RIGHT) x = x - (width);
if (valign == DTEXT_CENTER) y = y - (height / 2);
if (valign == DTEXT_BOTTOM) y = y - (height);
//TODO: line-discipline
for (int i = 0; str[i] != '\0' && i < size; ++i) {
dascii(x, y, fg, bg, str[i]);
x += font8x9.width + 1;
}
/* request draw call */
return dstack_add_action(
&DSTACK_CALL(
&dfont_text_render,
x, y,
fg, bg,
(uint32_t)(uintptr_t)str, size
),
(dtext_info.pool.idx == 0) ? (void*)&__dtext_quit : NULL,
NULL
);
}
/* dtext() : display text information */
void dtext(int x, int y, int fg, char const * restrict const text)
did_t dtext(int x, int y, int fg, char const * const text)
{
dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, text, -1);
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, text, -1));
}
void dprint(int x, int y, int fg, char const * const text, ...)
/* dprint() : display formated string */
did_t dprint(int x, int y, int fg, char const * const text, ...)
{
va_list ap;
char buff[1024];
@ -54,6 +150,22 @@ void dprint(int x, int y, int fg, char const * const text, ...)
vsnprintf(buff, 1024, text, ap);
va_end(ap);
dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, buff, -1);
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT, DTEXT_TOP, buff, -1));
}
/* dprint_opt(): Display a string of text */
did_t dprint_opt(
int x, int y,
int fg, int bg,
int halign, int valign,
char const *text, ...
) {
va_list ap;
char buff[1024];
va_start(ap, text);
vsnprintf(buff, 1024, text, ap);
va_end(ap);
return (dtext_opt(x, y, fg, bg, halign, valign, buff, -1));
}
#endif