mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 12:05:14 -04:00
C client: Initial implementation of system fonts, still has some major issues
This commit is contained in:
parent
edee08786e
commit
be6ec666a7
@ -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;
|
||||||
|
186
src/Platform.c
186
src/Platform.c
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user