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;
StringsBuffer fonts_list;
static void Font_Init(void);
static Int32 Font_Find(const String* name) {
Int32 i; Int32 i;
char nameBuffer[LF_FACESIZE]; for (i = 1; i < fonts_list.Count; i += 2) {
String name = String_FromArray(nameBuffer); String faceName = StringsBuffer_UNSAFE_Get(&fonts_list, i);
if (String_CaselessEquals(&faceName, name)) return i;
/* don't want international variations of font names too */
if (desc->lfFaceName[0] == '@' || desc->lfCharSet != ANSI_CHARSET) return 1;
if ((fontType & RASTER_FONTTYPE) || (fontType & TRUETYPE_FONTTYPE)) {
for (i = 0; i < LF_FACESIZE && desc->lfFaceName[i]; 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 };
font.lfHeight = -Math_CeilDiv(size * GetDeviceCaps(hdc, LOGPIXELSY), 72); if (!fonts_list.Count) Font_Init();
font.lfUnderline = style == FONT_STYLE_UNDERLINE; Int32 idx = Font_Find(fontName);
font.lfWeight = style == FONT_STYLE_BOLD ? FW_BOLD : FW_NORMAL; if (idx == -1) ErrorHandler_Fail("Unknown font");
font.lfQuality = ANTIALIASED_QUALITY; /* TODO: CLEARTYPE_QUALITY looks slightly better */
String dstName = String_Init(font.lfFaceName, 0, LF_FACESIZE); char pathBuffer[FILENAME_SIZE + 1];
String_AppendString(&dstName, fontName); String path = String_NT_Array(pathBuffer);
desc->Handle = CreateFontIndirectA(&font); StringsBuffer_Get(&fonts_list, idx - 1, &path);
if (!desc->Handle) ErrorHandler_Fail("Creating font handle failed"); path.buffer[path.length] = '\0';
FT_Face face;
FT_Error err = FT_New_Face(lib, path.buffer, 0, &face);
if (err) ErrorHandler_Fail2(err, "Creating font failed");
desc->Handle = face;
err = FT_Set_Char_Size(face, size * 64, 0, 96, 0); /* TODO: Check error */
//if (err) ErrorHandler_Fail2(err, "Resizing font 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) {
char pathBuffer[MAX_PATH * 5 + 1];
String path = String_NT_Array(pathBuffer);
String* dir = obj;
String_Format2(&path, "%s%s", dir, filename);
path.buffer[path.length] = '\0';
FT_Face face;
FT_Error error = FT_New_Face(lib, path.buffer, 0, &face);
if (error) return;
bool styled = (face->style_flags & FT_STYLE_FLAG_BOLD) || (face->style_flags & FT_STYLE_FLAG_ITALIC);
if (!styled) {
StringsBuffer_Add(&fonts_list, &path);
path.length = 0;
String_AppendConst(&path, face->family_name);
/* don't want 'Arial Regular' */
if (face->style_name) {
String style = String_FromReadonly(face->style_name);
if (!String_CaselessEqualsConst(&style, "Regular")) {
String_Format1(&path, " %c", face->style_name);
}
}
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) { Size2D Platform_TextMeasure(struct DrawTextArgs* args) {
WCHAR str[300]; Platform_ConvertString(str, &args->Text); FT_Face face = args->Font.Handle;
HGDIOBJ oldFont = SelectObject(hdc, args->Font.Handle); String text = args->Text;
SIZE area; GetTextExtentPointW(hdc, str, args->Text.length, &area); Size2D s = { 0, face->height };
Int32 i;
SelectObject(hdc, oldFont); for (i = 0; i < text.length; i++) {
Size2D s = { area.cx, area.cy }; return s; UInt16 c = Convert_CP437ToUnicode(text.buffer[i]);
FT_Load_Char(face, c, 0); /* TODO: Check error */
s.Width += face->glyph->advance.x;
} }
HBITMAP platform_dib; s.Width = TEXT_CEIL(s.Width);
HBITMAP platform_oldBmp; s.Height = TEXT_CEIL(s.Height);
Bitmap* platform_bmp; return s;
void* platform_bits;
void Platform_SetBitmap(Bitmap* bmp) {
platform_bmp = bmp;
platform_bits = NULL;
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = bmp->Width;
bmi.bmiHeader.biHeight = -bmp->Height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
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 */ Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, Int32 x, Int32 y, PackedCol col) {
/* TODO: make text prettier.. somehow? */ FT_Face face = args->Font.Handle;
/* TODO: Do we need to / 255 instead of >> 8 ? */ String text = args->Text;
Size2D Platform_TextDraw(struct DrawTextArgs* args, Int32 x, Int32 y, PackedCol col) { Size2D s = { 0, face->height };
WCHAR str[300]; Platform_ConvertString(str, &args->Text); Int32 i;
HGDIOBJ oldFont = (HFONT)SelectObject(hdc, (HFONT)args->Font.Handle); for (i = 0; i < text.length; i++) {
SIZE area; GetTextExtentPointW(hdc, str, args->Text.length, &area); UInt16 c = Convert_CP437ToUnicode(text.buffer[i]);
TextOutW(hdc, 0, 0, str, args->Text.length); FT_Load_Char(face, c, FT_LOAD_RENDER); /* TODO: Check error */
FT_Bitmap* img = &face->glyph->bitmap;
Int32 xx, yy; 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++) { 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; UInt8 intensity = *src, invIntensity = UInt8_MaxValue - intensity;
dst[0] = ((col.B * intensity) >> 8) + ((dst[0] * invIntensity) >> 8); dst[0] = ((col.B * intensity) >> 8) + ((dst[0] * invIntensity) >> 8);
dst[1] = ((col.G * intensity) >> 8) + ((dst[1] * invIntensity) >> 8); dst[1] = ((col.G * intensity) >> 8) + ((dst[1] * invIntensity) >> 8);
dst[2] = ((col.R * intensity) >> 8) + ((dst[2] * invIntensity) >> 8); dst[2] = ((col.R * intensity) >> 8) + ((dst[2] * invIntensity) >> 8);
//dst[3] = ((col.A * intensity) >> 8) + ((dst[3] * invIntensity) >> 8); //dst[3] = ((col.A * intensity) >> 8) + ((dst[3] * invIntensity) >> 8);
dst[3] = intensity + ((dst[3] * invIntensity) >> 8); dst[3] = intensity + ((dst[3] * invIntensity) >> 8);
src += BITMAP_SIZEOF_PIXEL; dst += BITMAP_SIZEOF_PIXEL; src++; dst += BITMAP_SIZEOF_PIXEL;
} }
} }
x += face->glyph->advance.x >> 6;
SelectObject(hdc, oldFont);
//DrawTextA(hdc, args->Text.buffer, args->Text.length,
// &r, DT_NOPREFIX | DT_SINGLELINE | DT_NOCLIP);
Size2D s = { area.cx, area.cy }; return s;
} }
void Platform_ReleaseBitmap(void) { s.Width = TEXT_CEIL(s.Width);
/* TODO: Check return values */ s.Height = TEXT_CEIL(s.Height);
SelectObject(hdc, platform_oldBmp); return s;
DeleteObject(platform_dib); }
platform_oldBmp = NULL; #if CC_BUILD_WIN
platform_dib = NULL; static void Font_Init(void) {
platform_bmp = NULL; 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);