WIP on very basic platform independent system font backend

This commit is contained in:
UnknownShadow200 2023-09-30 09:11:21 +10:00
parent 0c2b52efe7
commit b07f6575ba
4 changed files with 271 additions and 8 deletions

41
misc/bitmap_font_gen.cs Normal file
View file

@ -0,0 +1,41 @@
void Main()
{
Console.WriteLine("static cc_uint8 font_bitmap[][8] = {");
using (Bitmap bmp = new Bitmap(@"C:\classicube-dev\default.png"))
{
for (int CY = 0; CY < 16; CY++)
for (int CX = 0; CX < 16; CX++)
DecodeTile(bmp, CX, CY);
}
Console.WriteLine("}");
}
static void DecodeTile(Bitmap bmp, int cx, int cy) {
int c = (cy << 4) | cx;
if (c <= 32 || c >= 127) return;
int X = cx * 8, Y = cy * 8;
Console.Write("\t{ ");
for (int y = Y; y < Y + 8; y++) {
uint mask = 0;
int shift = 0;
for (int x = X; x < X + 8; x++, shift++) {
Color P = bmp.GetPixel(x, y);
if (P.A == 0) {
mask |= 0u << shift;
} else if (P.R == 255 && P.G == 255 && P.B == 255 && P.A == 255) {
mask |= 1u << shift;
} else {
throw new InvalidOperationException("unsupported colour" + P);
}
}
string suffix = y == Y + 7 ? " " : ",";
Console.Write("0x" + mask.ToString("X2") + suffix);
}
Console.WriteLine("}, /* " + (char)c + " */");
}

View file

@ -4,8 +4,10 @@ SOURCE_DIRS := src third_party/bearssl/src
C_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
OBJS := $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o)))
CFLAGS :=-g -O1 -pipe -fno-math-errno -Ithird_party/bearssl/inc
GLDC_LIB=third_party/gldc/libGLdc.a
LDFLAGS=-g
LIBS=-lm
LIBS=-lm $(GLDC_LIB)
TARGET := ClassiCube-dc
@ -13,11 +15,14 @@ ifeq ($(strip $(KOS_BASE)),)
$(error "Please set KOS variables in your environment.")
endif
default: $(BUILD_DIR) $(TARGET).cdi
default: $(GLDC_LIB) $(BUILD_DIR) $(TARGET).cdi
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(GLDC_LIB):
$(MAKE) -C third_party/gldc
$(BUILD_DIR)/%.o: src/%.c
kos-cc $(CFLAGS) -c $< -o $@

View file

@ -1419,4 +1419,223 @@ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int
}
}
}
#else
#define SysFont_ValidChar(c) ((c) > 32 && (c) < 127)
#define SysFont_ToIndex(c) ((c) - 33) /* First valid char is ! */
#define SPACE_WIDTH 2
#define CELL_SIZE 8
#define SysFont_GetRows(c) (SysFont_ValidChar(c) ? font_bitmap[SysFont_ToIndex(c)] : missing_cell)
static cc_uint8 missing_cell[CELL_SIZE] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};
/* 8x8 font bitmap, represented with 1 bit for each pixel */
/* Source: Goodly's texture pack for ClassiCube */
static cc_uint8 font_bitmap[][CELL_SIZE] = {
{ 0x01,0x01,0x01,0x01,0x01,0x00,0x01,0x00 }, /* ! */
{ 0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00 }, /* " */
{ 0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A,0x00 }, /* # */
{ 0x04,0x1F,0x01,0x1F,0x10,0x1F,0x04,0x00 }, /* $ */
{ 0x00,0x21,0x11,0x08,0x04,0x22,0x21,0x00 }, /* % */
{ 0x0C,0x12,0x0C,0x2E,0x19,0x11,0x2E,0x00 }, /* & */
{ 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, /* ' */
{ 0x04,0x02,0x01,0x01,0x01,0x02,0x04,0x00 }, /* ( */
{ 0x01,0x02,0x04,0x04,0x04,0x02,0x01,0x00 }, /* ) */
{ 0x00,0x02,0x07,0x02,0x05,0x00,0x00,0x00 }, /* * */
{ 0x00,0x04,0x04,0x1F,0x04,0x04,0x00,0x00 }, /* + */
{ 0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01 }, /* , */
{ 0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00 }, /* - */
{ 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00 }, /* . */
{ 0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x00 }, /* / */
{ 0x06,0x09,0x0D,0x0B,0x09,0x09,0x06,0x00 }, /* 0 */
{ 0x02,0x03,0x02,0x02,0x02,0x02,0x07,0x00 }, /* 1 */
{ 0x06,0x09,0x08,0x04,0x02,0x09,0x0F,0x00 }, /* 2 */
{ 0x06,0x09,0x08,0x06,0x08,0x09,0x06,0x00 }, /* 3 */
{ 0x05,0x05,0x05,0x0F,0x04,0x04,0x04,0x00 }, /* 4 */
{ 0x0F,0x01,0x07,0x08,0x08,0x09,0x06,0x00 }, /* 5 */
{ 0x06,0x09,0x01,0x07,0x09,0x09,0x06,0x00 }, /* 6 */
{ 0x0F,0x08,0x08,0x04,0x04,0x02,0x02,0x00 }, /* 7 */
{ 0x06,0x09,0x09,0x06,0x09,0x09,0x06,0x00 }, /* 8 */
{ 0x06,0x09,0x09,0x0E,0x08,0x09,0x06,0x00 }, /* 9 */
{ 0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00 }, /* : */
{ 0x00,0x02,0x02,0x00,0x00,0x02,0x02,0x01 }, /* ; */
{ 0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00 }, /* < */
{ 0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00 }, /* = */
{ 0x00,0x01,0x02,0x04,0x02,0x01,0x00,0x00 }, /* > */
{ 0x07,0x09,0x08,0x04,0x02,0x00,0x02,0x00 }, /* ? */
{ 0x0E,0x11,0x1D,0x1D,0x1D,0x01,0x0E,0x00 }, /* @ */
{ 0x06,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* A */
{ 0x07,0x09,0x09,0x07,0x09,0x09,0x07,0x00 }, /* B */
{ 0x06,0x09,0x01,0x01,0x01,0x09,0x06,0x00 }, /* C */
{ 0x07,0x09,0x09,0x09,0x09,0x09,0x07,0x00 }, /* D */
{ 0x0F,0x01,0x01,0x07,0x01,0x01,0x0F,0x00 }, /* E */
{ 0x0F,0x01,0x01,0x07,0x01,0x01,0x01,0x00 }, /* F */
{ 0x06,0x09,0x01,0x0D,0x09,0x09,0x06,0x00 }, /* G */
{ 0x09,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* H */
{ 0x07,0x02,0x02,0x02,0x02,0x02,0x07,0x00 }, /* I */
{ 0x08,0x08,0x08,0x08,0x08,0x09,0x07,0x00 }, /* J */
{ 0x09,0x09,0x05,0x03,0x05,0x09,0x09,0x00 }, /* K */
{ 0x01,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, /* L */
{ 0x11,0x1B,0x15,0x11,0x11,0x11,0x11,0x00 }, /* M */
{ 0x09,0x0B,0x0D,0x09,0x09,0x09,0x09,0x00 }, /* N */
{ 0x06,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* O */
{ 0x07,0x09,0x09,0x07,0x01,0x01,0x01,0x00 }, /* P */
{ 0x06,0x09,0x09,0x09,0x09,0x05,0x0E,0x00 }, /* Q */
{ 0x07,0x09,0x09,0x07,0x09,0x09,0x09,0x00 }, /* R */
{ 0x06,0x09,0x01,0x06,0x08,0x09,0x06,0x00 }, /* S */
{ 0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x00 }, /* T */
{ 0x09,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* U */
{ 0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00 }, /* V */
{ 0x11,0x11,0x11,0x11,0x15,0x1B,0x11,0x00 }, /* W */
{ 0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00 }, /* X */
{ 0x11,0x11,0x0A,0x04,0x04,0x04,0x04,0x00 }, /* Y */
{ 0x0F,0x08,0x04,0x02,0x01,0x01,0x0F,0x00 }, /* Z */
{ 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00 }, /* [ */
{ 0x01,0x01,0x02,0x02,0x04,0x04,0x08,0x00 }, /* \ */
{ 0x07,0x04,0x04,0x04,0x04,0x04,0x07,0x00 }, /* ] */
{ 0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00 }, /* ^ */
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F }, /* _ */
{ 0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00 }, /* ` */
{ 0x00,0x00,0x0E,0x09,0x09,0x0D,0x0B,0x00 }, /* a */
{ 0x01,0x01,0x07,0x09,0x09,0x09,0x07,0x00 }, /* b */
{ 0x00,0x00,0x06,0x09,0x01,0x09,0x06,0x00 }, /* c */
{ 0x08,0x08,0x0E,0x09,0x09,0x09,0x0E,0x00 }, /* d */
{ 0x00,0x00,0x06,0x09,0x0F,0x01,0x0E,0x00 }, /* e */
{ 0x06,0x01,0x07,0x01,0x01,0x01,0x01,0x00 }, /* f */
{ 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x07 }, /* g */
{ 0x01,0x01,0x07,0x09,0x09,0x09,0x09,0x00 }, /* h */
{ 0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x00 }, /* i */
{ 0x08,0x00,0x08,0x08,0x08,0x08,0x09,0x06 }, /* j */
{ 0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00 }, /* k */
{ 0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x00 }, /* l */
{ 0x00,0x00,0x0B,0x15,0x15,0x11,0x11,0x00 }, /* m */
{ 0x00,0x00,0x07,0x09,0x09,0x09,0x09,0x00 }, /* n */
{ 0x00,0x00,0x06,0x09,0x09,0x09,0x06,0x00 }, /* o */
{ 0x00,0x00,0x07,0x09,0x09,0x07,0x01,0x01 }, /* p */
{ 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x08 }, /* q */
{ 0x00,0x00,0x05,0x03,0x01,0x01,0x01,0x00 }, /* r */
{ 0x00,0x00,0x0E,0x01,0x06,0x08,0x07,0x00 }, /* s */
{ 0x02,0x02,0x07,0x02,0x02,0x02,0x02,0x00 }, /* t */
{ 0x00,0x00,0x09,0x09,0x09,0x09,0x0E,0x00 }, /* u */
{ 0x00,0x00,0x09,0x09,0x09,0x05,0x03,0x00 }, /* v */
{ 0x00,0x00,0x11,0x11,0x15,0x15,0x1A,0x00 }, /* w */
{ 0x00,0x00,0x05,0x05,0x02,0x05,0x05,0x00 }, /* x */
{ 0x00,0x00,0x09,0x09,0x09,0x0E,0x08,0x07 }, /* y */
{ 0x00,0x00,0x0F,0x08,0x04,0x02,0x0F,0x00 }, /* z */
{ 0x04,0x02,0x02,0x01,0x02,0x02,0x04,0x00 }, /* { */
{ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, /* | */
{ 0x01,0x02,0x02,0x04,0x02,0x02,0x01,0x00 }, /* } */
{ 0x00,0x00,0x26,0x19,0x00,0x00,0x00,0x00 }, /* ~ */
};
void SysFonts_Register(const cc_string* path) { }
const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; }
void SysFonts_GetNames(struct StringsBuffer* buffer) { }
cc_result SysFont_Make(struct FontDesc* desc, const cc_string* fontName, int size, int flags) {
desc->size = size;
desc->flags = flags;
desc->height = Drawer2D_AdjHeight(size);
desc->handle = (void*)1;
return 0;
}
void SysFont_MakeDefault(struct FontDesc* desc, int size, int flags) {
SysFont_Make(desc, NULL, size, flags);
}
void SysFont_Free(struct FontDesc* desc) {
}
static int CellWidth(cc_uint8* rows) {
int y, widest = 0;
for (y = 0; y < CELL_SIZE; y++)
{
widest = max(widest, rows[y]);
}
return Math_Log2(widest) + 2; /* add padding for next character */
}
int SysFont_TextWidth(struct DrawTextArgs* args) {
int width = 0;
cc_string left = args->text, part;
char colorCode = 'f';
int i;
while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode))
{
for (i = 0; i < part.length; i++)
{
cc_uint8 c = part.buffer[i];
if (c == ' ') {
width += SPACE_WIDTH;
} else {
width += CellWidth(SysFont_GetRows(c));
}
}
}
width = max(1, width);
if (args->useShadow) width++;
return width;
}
static void DrawCell(struct Bitmap* bmp, int x, int y, cc_uint8* rows, BitmapCol color) {
int srcX, srcY, dstX, dstY;
cc_uint8 row;
for (srcY = 0; srcY < CELL_SIZE; srcY++)
{
dstY = y + srcY;
if (dstY < 0 || dstY >= bmp->height) continue;
row = rows[srcY];
for (srcX = 0; srcX < CELL_SIZE; srcX++)
{
dstX = x + srcX;
if (dstX < 0 || dstX >= bmp->width) continue;
if (row & (1 << srcX)) {
Bitmap_GetPixel(bmp, dstX, dstY) = color;
}
}
}
}
void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) {
cc_string left = args->text, part;
char colorCode = 'f';
cc_uint8* rows;
BitmapCol color;
int i;
if (shadow) { x++; y++; }
while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode))
{
color = Drawer2D_GetColor(colorCode);
if (shadow) color = GetShadowColor(color);
for (i = 0; i < part.length; i++)
{
cc_uint8 c = part.buffer[i];
if (c == ' ') {
x += SPACE_WIDTH;
} else {
rows = SysFont_GetRows(c);
DrawCell(bmp, x, y, rows, color);
x += CellWidth(rows);
}
}
}
}
#endif

View file

@ -3,12 +3,10 @@ SOURCE_DIRS := src src/yalloc
C_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
OBJS := $(notdir $(C_FILES:%.c=%.o))
C_FLAGS = -O3 -DNDEBUG -mfsrra -mfsca -ffp-contract=fast -ffast-math -O3 -mpretend-cmove -fexpensive-optimizations -fomit-frame-pointer -finline-functions -flto -fno-fat-lto-objects -ml -m4-single-only -ffunction-sections -fdata-sections -std=gnu99
C_FLAGS = -O3 -DNDEBUG -mfsrra -mfsca -ffp-contract=fast -ffast-math -O3 -mpretend-cmove -fexpensive-optimizations -fomit-frame-pointer -finline-functions -flto -fno-fat-lto-objects -ml -m4-single-only -ffunction-sections -fdata-sections -std=gnu99
C_DEFINES = -DDREAMCAST -DNDEBUG -D__DREAMCAST__ -D__arch_dreamcast -D_arch_dreamcast -D_arch_sub_pristine
C_INCLUDES = -I/opt/toolchains/dc/kos/include -I/opt/toolchains/dc/kos/kernel/arch/dreamcast/include -I/opt/toolchains/dc/kos/addons/include
TARGET := libGLdc.a
ifeq ($(strip $(KOS_BASE)),)
@ -18,10 +16,10 @@ endif
default: $(TARGET)
%.o: src/%.c
kos-cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -c $< -o $@
kos-cc $(C_DEFINES) $(C_FLAGS) -c $< -o $@
%.o: src/yalloc/%.c
kos-cc $(C_DEFINES) $(C_INCLUDES) $(C_FLAGS) -c $< -o $@
kos-cc $(C_DEFINES) $(C_FLAGS) -c $< -o $@
$(TARGET): $(OBJS)
kos-ar cr $@ $^