C client: Initial implementation of system fonts, still has some major issues

This commit is contained in:
UnknownShadow200 2018-09-30 17:56:50 +10:00
parent edee08786e
commit be6ec666a7
3 changed files with 130 additions and 110 deletions

View File

@ -104,19 +104,9 @@ void Drawer2D_Init(void) {
} }
} }
void Drawer2D_Free(void) { void Drawer2D_Free(void) { Drawer2D_FreeFontBitmap(); }
Drawer2D_FreeFontBitmap(); void Drawer2D_Begin(Bitmap* bmp) { Drawer2D_Cur = bmp; }
} void Drawer2D_End(void) { Drawer2D_Cur = NULL; }
void Drawer2D_Begin(Bitmap* bmp) {
if (!Drawer2D_BitmappedText) Platform_SetBitmap(bmp);
Drawer2D_Cur = bmp;
}
void Drawer2D_End(void) {
if (!Drawer2D_BitmappedText) Platform_ReleaseBitmap();
Drawer2D_Cur = NULL;
}
/* Draws a 2D flat rectangle. */ /* Draws a 2D flat rectangle. */
void Drawer2D_Rect(Bitmap* bmp, PackedCol col, Int32 x, Int32 y, Int32 width, Int32 height); void Drawer2D_Rect(Bitmap* bmp, PackedCol col, Int32 x, Int32 y, Int32 width, Int32 height);
@ -397,10 +387,10 @@ void Drawer2D_DrawText(struct DrawTextArgs* args, Int32 x, Int32 y) {
if (args->UseShadow) { if (args->UseShadow) {
PackedCol black = PACKEDCOL_BLACK; PackedCol black = PACKEDCOL_BLACK;
PackedCol backCol = Drawer2D_BlackTextShadows ? black : PackedCol_Scale(col, 0.25f); PackedCol backCol = Drawer2D_BlackTextShadows ? black : PackedCol_Scale(col, 0.25f);
Platform_TextDraw(args, x + DRAWER2D_OFFSET, y + DRAWER2D_OFFSET, backCol); Platform_TextDraw(args, Drawer2D_Cur, x + DRAWER2D_OFFSET, y + DRAWER2D_OFFSET, backCol);
} }
Size2D partSize = Platform_TextDraw(args, x, y, col); Size2D partSize = Platform_TextDraw(args, Drawer2D_Cur, x, y, col);
x += partSize.Width; x += partSize.Width;
} }
args->Text = value; args->Text = value;

View File

@ -9,6 +9,9 @@
#include "AsyncDownloader.h" #include "AsyncDownloader.h"
#include "Bitmap.h" #include "Bitmap.h"
#include "freetype/ft2build.h"
#include "freetype/freetype.h"
#if CC_BUILD_WIN #if CC_BUILD_WIN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define NOSERVICE #define NOSERVICE
@ -670,42 +673,50 @@ void Waitable_WaitFor(void* handle, UInt32 milliseconds) {
/*########################################################################################################################* /*########################################################################################################################*
*--------------------------------------------------------Font/Text--------------------------------------------------------* *--------------------------------------------------------Font/Text--------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
#if CC_BUILD_WIN #include "freetype\ftsnames.h"
int CALLBACK Font_GetNamesCallback(CONST LOGFONT* desc, CONST TEXTMETRIC* metrics, DWORD fontType, LPVOID obj) { FT_Library lib;
Int32 i; StringsBuffer fonts_list;
char nameBuffer[LF_FACESIZE]; static void Font_Init(void);
String name = String_FromArray(nameBuffer);
/* don't want international variations of font names too */ static Int32 Font_Find(const String* name) {
if (desc->lfFaceName[0] == '@' || desc->lfCharSet != ANSI_CHARSET) return 1; Int32 i;
for (i = 1; i < fonts_list.Count; i += 2) {
if ((fontType & RASTER_FONTTYPE) || (fontType & TRUETYPE_FONTTYPE)) { String faceName = StringsBuffer_UNSAFE_Get(&fonts_list, i);
for (i = 0; i < LF_FACESIZE && desc->lfFaceName[i]; i++) { if (String_CaselessEquals(&faceName, name)) return i;
String_Append(&name, Convert_UnicodeToCP437(desc->lfFaceName[i]));
}
StringsBuffer_Add((StringsBuffer*)obj, &name);
} }
return 1; return -1;
} }
void Font_GetNames(StringsBuffer* buffer) { void Font_GetNames(StringsBuffer* buffer) {
EnumFontFamiliesW(hdc, NULL, Font_GetNamesCallback, buffer); if (!fonts_list.Count) Font_Init();
Int32 i;
for (i = 1; i < fonts_list.Count; i += 2) {
String faceName = StringsBuffer_UNSAFE_Get(&fonts_list, i);
StringsBuffer_Add(buffer, &faceName);
}
} }
void Font_Make(FontDesc* desc, const String* fontName, UInt16 size, UInt16 style) { void Font_Make(FontDesc* desc, const String* fontName, UInt16 size, UInt16 style) {
desc->Size = size; desc->Size = size;
desc->Style = style; desc->Style = style;
LOGFONTA font = { 0 };
if (!fonts_list.Count) Font_Init();
Int32 idx = Font_Find(fontName);
if (idx == -1) ErrorHandler_Fail("Unknown font");
char pathBuffer[FILENAME_SIZE + 1];
String path = String_NT_Array(pathBuffer);
StringsBuffer_Get(&fonts_list, idx - 1, &path);
path.buffer[path.length] = '\0';
font.lfHeight = -Math_CeilDiv(size * GetDeviceCaps(hdc, LOGPIXELSY), 72); FT_Face face;
font.lfUnderline = style == FONT_STYLE_UNDERLINE; FT_Error err = FT_New_Face(lib, path.buffer, 0, &face);
font.lfWeight = style == FONT_STYLE_BOLD ? FW_BOLD : FW_NORMAL; if (err) ErrorHandler_Fail2(err, "Creating font failed");
font.lfQuality = ANTIALIASED_QUALITY; /* TODO: CLEARTYPE_QUALITY looks slightly better */ desc->Handle = face;
String dstName = String_Init(font.lfFaceName, 0, LF_FACESIZE); err = FT_Set_Char_Size(face, size * 64, 0, 96, 0); /* TODO: Check error */
String_AppendString(&dstName, fontName); //if (err) ErrorHandler_Fail2(err, "Resizing font failed");
desc->Handle = CreateFontIndirectA(&font);
if (!desc->Handle) ErrorHandler_Fail("Creating font handle failed");
} }
void Font_Free(FontDesc* desc) { void Font_Free(FontDesc* desc) {
@ -714,83 +725,104 @@ void Font_Free(FontDesc* desc) {
/* NULL for fonts created by Drawer2D_MakeFont and bitmapped text mode is on */ /* NULL for fonts created by Drawer2D_MakeFont and bitmapped text mode is on */
if (!desc->Handle) return; if (!desc->Handle) return;
if (!DeleteObject(desc->Handle)) ErrorHandler_Fail("Deleting font handle failed"); FT_Face face = desc->Handle;
FT_Error err = FT_Done_Face(face);
if (err) ErrorHandler_Fail2(err, "Deleting font failed");
desc->Handle = NULL; desc->Handle = NULL;
} }
/* TODO: not associate font with device so much */ static void Font_DirCallback(const String* filename, void* obj) {
Size2D Platform_TextMeasure(struct DrawTextArgs* args) { char pathBuffer[MAX_PATH * 5 + 1];
WCHAR str[300]; Platform_ConvertString(str, &args->Text); String path = String_NT_Array(pathBuffer);
HGDIOBJ oldFont = SelectObject(hdc, args->Font.Handle); String* dir = obj;
SIZE area; GetTextExtentPointW(hdc, str, args->Text.length, &area);
SelectObject(hdc, oldFont); String_Format2(&path, "%s%s", dir, filename);
Size2D s = { area.cx, area.cy }; return s; path.buffer[path.length] = '\0';
}
HBITMAP platform_dib; FT_Face face;
HBITMAP platform_oldBmp; FT_Error error = FT_New_Face(lib, path.buffer, 0, &face);
Bitmap* platform_bmp; if (error) return;
void* platform_bits;
void Platform_SetBitmap(Bitmap* bmp) { bool styled = (face->style_flags & FT_STYLE_FLAG_BOLD) || (face->style_flags & FT_STYLE_FLAG_ITALIC);
platform_bmp = bmp; if (!styled) {
platform_bits = NULL; StringsBuffer_Add(&fonts_list, &path);
path.length = 0;
BITMAPINFO bmi = { 0 }; String_AppendConst(&path, face->family_name);
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); /* don't want 'Arial Regular' */
bmi.bmiHeader.biWidth = bmp->Width; if (face->style_name) {
bmi.bmiHeader.biHeight = -bmp->Height; String style = String_FromReadonly(face->style_name);
bmi.bmiHeader.biPlanes = 1; if (!String_CaselessEqualsConst(&style, "Regular")) {
bmi.bmiHeader.biBitCount = 32; String_Format1(&path, " %c", face->style_name);
bmi.bmiHeader.biCompression = BI_RGB; }
platform_dib = CreateDIBSection(hdc, &bmi, 0, &platform_bits, NULL, 0);
if (!platform_dib) ErrorHandler_Fail("Failed to allocate DIB for text");
platform_oldBmp = SelectObject(hdc, platform_dib);
}
/* TODO: check return codes and stuff */
/* TODO: make text prettier.. somehow? */
/* TODO: Do we need to / 255 instead of >> 8 ? */
Size2D Platform_TextDraw(struct DrawTextArgs* args, Int32 x, Int32 y, PackedCol col) {
WCHAR str[300]; Platform_ConvertString(str, &args->Text);
HGDIOBJ oldFont = (HFONT)SelectObject(hdc, (HFONT)args->Font.Handle);
SIZE area; GetTextExtentPointW(hdc, str, args->Text.length, &area);
TextOutW(hdc, 0, 0, str, args->Text.length);
Int32 xx, yy;
Bitmap* bmp = platform_bmp;
for (yy = 0; yy < area.cy; yy++) {
UInt8* src = (UInt8*)platform_bits + (yy * (bmp->Width << 2));
UInt8* dst = (UInt8*)Bitmap_GetRow(bmp, y + yy); dst += x * BITMAP_SIZEOF_PIXEL;
for (xx = 0; xx < area.cx; xx++) {
UInt8 intensity = *src, invIntensity = UInt8_MaxValue - intensity;
dst[0] = ((col.B * intensity) >> 8) + ((dst[0] * invIntensity) >> 8);
dst[1] = ((col.G * intensity) >> 8) + ((dst[1] * invIntensity) >> 8);
dst[2] = ((col.R * intensity) >> 8) + ((dst[2] * invIntensity) >> 8);
//dst[3] = ((col.A * intensity) >> 8) + ((dst[3] * invIntensity) >> 8);
dst[3] = intensity + ((dst[3] * invIntensity) >> 8);
src += BITMAP_SIZEOF_PIXEL; dst += BITMAP_SIZEOF_PIXEL;
} }
Platform_Log1("Face: %s", &path);
StringsBuffer_Add(&fonts_list, &path);
}
FT_Done_Face(face);
}
#define TEXT_CEIL(x) (((x) + 63) >> 6)
Size2D Platform_TextMeasure(struct DrawTextArgs* args) {
FT_Face face = args->Font.Handle;
String text = args->Text;
Size2D s = { 0, face->height };
Int32 i;
for (i = 0; i < text.length; i++) {
UInt16 c = Convert_CP437ToUnicode(text.buffer[i]);
FT_Load_Char(face, c, 0); /* TODO: Check error */
s.Width += face->glyph->advance.x;
} }
SelectObject(hdc, oldFont); s.Width = TEXT_CEIL(s.Width);
//DrawTextA(hdc, args->Text.buffer, args->Text.length, s.Height = TEXT_CEIL(s.Height);
// &r, DT_NOPREFIX | DT_SINGLELINE | DT_NOCLIP); return s;
Size2D s = { area.cx, area.cy }; return s;
} }
void Platform_ReleaseBitmap(void) { Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, Int32 x, Int32 y, PackedCol col) {
/* TODO: Check return values */ FT_Face face = args->Font.Handle;
SelectObject(hdc, platform_oldBmp); String text = args->Text;
DeleteObject(platform_dib); Size2D s = { 0, face->height };
Int32 i;
platform_oldBmp = NULL; for (i = 0; i < text.length; i++) {
platform_dib = NULL; UInt16 c = Convert_CP437ToUnicode(text.buffer[i]);
platform_bmp = NULL; FT_Load_Char(face, c, FT_LOAD_RENDER); /* TODO: Check error */
FT_Bitmap* img = &face->glyph->bitmap;
Int32 xx, yy;
for (yy = 0; yy < img->rows; yy++) {
UInt8* src = img->buffer + (yy * img->width);
UInt8* dst = (UInt8*)Bitmap_GetRow(bmp, y + yy) + (x * BITMAP_SIZEOF_PIXEL);
for (xx = 0; xx < img->width; xx++) {
if ((x + xx) < 0 || (y + yy) < 0 || (x + xx) >= bmp->Width || (y + yy) >= bmp->Height) continue;
UInt8 intensity = *src, invIntensity = UInt8_MaxValue - intensity;
dst[0] = ((col.B * intensity) >> 8) + ((dst[0] * invIntensity) >> 8);
dst[1] = ((col.G * intensity) >> 8) + ((dst[1] * invIntensity) >> 8);
dst[2] = ((col.R * intensity) >> 8) + ((dst[2] * invIntensity) >> 8);
//dst[3] = ((col.A * intensity) >> 8) + ((dst[3] * invIntensity) >> 8);
dst[3] = intensity + ((dst[3] * invIntensity) >> 8);
src++; dst += BITMAP_SIZEOF_PIXEL;
}
}
x += face->glyph->advance.x >> 6;
}
s.Width = TEXT_CEIL(s.Width);
s.Height = TEXT_CEIL(s.Height);
return s;
}
#if CC_BUILD_WIN
static void Font_Init(void) {
FT_Error err = FT_Init_FreeType(&lib);
String dir = String_FromConst("C:\\Windows\\fonts\\");
Directory_Enum(&dir, &dir, Font_DirCallback);
} }
#elif CC_BUILD_NIX #elif CC_BUILD_NIX
#endif #endif

View File

@ -86,13 +86,11 @@ void Waitable_Signal(void* handle);
void Waitable_Wait(void* handle); void Waitable_Wait(void* handle);
void Waitable_WaitFor(void* handle, UInt32 milliseconds); void Waitable_WaitFor(void* handle, UInt32 milliseconds);
void Font_GetNames(StringsBuffer* buffer); NOINLINE_ void Font_GetNames(StringsBuffer* buffer);
NOINLINE_ void Font_Make(FontDesc* desc, const String* fontName, UInt16 size, UInt16 style); NOINLINE_ void Font_Make(FontDesc* desc, const String* fontName, UInt16 size, UInt16 style);
NOINLINE_ void Font_Free(FontDesc* desc); NOINLINE_ void Font_Free(FontDesc* desc);
Size2D Platform_TextMeasure(struct DrawTextArgs* args); NOINLINE_ Size2D Platform_TextMeasure(struct DrawTextArgs* args);
void Platform_SetBitmap(Bitmap* bmp); NOINLINE_ Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, Int32 x, Int32 y, PackedCol col);
Size2D Platform_TextDraw(struct DrawTextArgs* args, Int32 x, Int32 y, PackedCol col);
void Platform_ReleaseBitmap(void);
void Socket_Create(SocketPtr* socket); void Socket_Create(SocketPtr* socket);
ReturnCode Socket_Available(SocketPtr socket, UInt32* available); ReturnCode Socket_Available(SocketPtr socket, UInt32* available);