diff --git a/CMakeLists.txt b/CMakeLists.txt index d3e11c3..6d2f424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,8 @@ else() endif() option(CLASSIC "Use classic theme" OFF) option(USE_STB_IMAGE "Use stb_image" ON) -option(USE_STB_TRUETYPE "Use stb_truetype" ON) +option(USE_STB_TRUETYPE "Use stb_truetype" OFF) +option(USE_FREETYPE2 "Use FreeType 2" ON) file( GLOB @@ -76,6 +77,20 @@ if(USE_STB_TRUETYPE) ) endif() +if(USE_FREETYPE2) + target_compile_definitions( + Mw + PRIVATE + USE_FREETYPE2 + ) + + find_package(PkgConfig) + pkg_check_modules(FT2 REQUIRED freetype2) + list(APPEND INCLUDE_DIRS ${FT2_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${FT2_LIBRARY_DIRS}) + list(APPEND LIBRARIES ${FT2_LIBRARIES}) +endif() + target_include_directories( Mw PRIVATE diff --git a/GNUmakefile b/GNUmakefile index 2335542..f45cadc 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -5,9 +5,13 @@ PREFIX = /usr/local ifeq ($(TARGET),) TARGET = $(shell uname -s) endif +ifneq ($(TARGET),$(shell uname -s)) +CROSS = 1 +endif USE_STB_IMAGE = 1 -USE_STB_TRUETYPE = 1 +USE_STB_TRUETYPE = 0 +USE_FREETYPE2 = 1 CC = $(GCC)gcc @@ -139,6 +143,15 @@ else include external/deps.mk endif +ifeq ($(USE_FREETYPE2),1) +L_CFLAGS += -DUSE_FREETYPE2 + +ifneq ($(CROSS),1) +L_CFLAGS += $(shell pkg-config --cflags freetype2) +L_LIBS += $(shell pkg-config --libs freetype2) +endif +endif + ifeq ($(USE_STB_TRUETYPE),1) L_CFLAGS += -DUSE_STB_TRUETYPE endif diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6d1b2d5..26debd5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,6 +9,11 @@ list(REMOVE_ITEM EXAMPLES_SOURCES ${CMAKE_SOURCE_DIR}/examples/harvard.c) foreach(PATH IN LISTS EXAMPLES_SOURCES) get_filename_component(TARGET ${PATH} NAME_WE) add_executable(${TARGET} ${PATH}) + target_include_directories( + ${TARGET} + PRIVATE + ${CMAKE_SOURCE_DIR}/include + ) target_link_libraries( ${TARGET} PRIVATE diff --git a/examples/basic/CMakeLists.txt b/examples/basic/CMakeLists.txt index 29abd29..69f087d 100644 --- a/examples/basic/CMakeLists.txt +++ b/examples/basic/CMakeLists.txt @@ -8,6 +8,11 @@ file( foreach(PATH IN LISTS EXAMPLES_BASIC_SOURCES) get_filename_component(TARGET ${PATH} NAME_WE) add_executable(${TARGET} ${PATH}) + target_include_directories( + ${TARGET} + PRIVATE + ${CMAKE_SOURCE_DIR}/include + ) target_link_libraries( ${TARGET} PRIVATE diff --git a/examples/color_picker.c b/examples/color_picker.c index 5613e81..2f7e2fd 100644 --- a/examples/color_picker.c +++ b/examples/color_picker.c @@ -1,7 +1,6 @@ /* $Id$ */ #include -#include MwWidget vp; #define WIN_SIZE 512 diff --git a/src/core.c b/src/core.c index 4c689cc..90f99f0 100644 --- a/src/core.c +++ b/src/core.c @@ -434,7 +434,7 @@ static void inherit_integer(MwWidget handle, const char* key, int default_value) MwSetInteger(handle, key, default_value); } -#ifdef USE_STB_TRUETYPE +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) static void set_font(MwWidget handle) { void* f; MwWidget h = handle; @@ -474,7 +474,7 @@ void MwSetDefault(MwWidget handle) { #else inherit_integer(handle, MwNmodernLook, 1); #endif -#ifdef USE_STB_TRUETYPE +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) set_font(handle); set_boldfont(handle); #endif diff --git a/src/text/boldttf.c b/src/text/boldttf.c index 6622ea6..3f5850e 100644 --- a/src/text/boldttf.c +++ b/src/text/boldttf.c @@ -1,7 +1,7 @@ /* $Id$ */ #include -#ifdef USE_STB_TRUETYPE +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) unsigned char MwBoldTTFData[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x10, 0x46, 0x46, 0x54, 0x4d, 0xab, 0xe1, 0x51, 0x39, 0x00, 0x00, 0x56, 0x68, diff --git a/src/text/draw.c b/src/text/draw.c index 5ce0593..71c97c3 100644 --- a/src/text/draw.c +++ b/src/text/draw.c @@ -1,7 +1,18 @@ /* $Id$ */ #include -#ifdef USE_STB_TRUETYPE +#if defined(USE_FREETYPE2) +#include +#include FT_FREETYPE_H + +typedef struct ttf { + FT_Library library; + FT_Face face; + void* data; +} ttf_t; + +#define TTF +#elif defined(USE_STB_TRUETYPE) #include "../../external/stb_truetype.h" typedef struct ttf { @@ -11,6 +22,8 @@ typedef struct ttf { int ascent; int descent; } ttf_t; + +#define TTF #endif #define FontWidth 7 @@ -80,10 +93,9 @@ static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, free(px); } -#ifdef USE_STB_TRUETYPE +#if defined(USE_STB_TRUETYPE) static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { ttf_t* ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); - MwLLColor base; unsigned char* px; int tw, th; MwRect r; @@ -92,8 +104,6 @@ static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int int x = 0; if(ttf == NULL) return 1; - base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - tw = MwTextWidth(handle, text); th = MwTextHeight(handle, text); px = malloc(tw * th * 4); @@ -149,12 +159,10 @@ static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int MwLLDestroyPixmap(p); free(px); - MwLLFreeColor(base); - return 0; } -int ttf_MwTextWidth(MwWidget handle, const char* text) { +static int ttf_MwTextWidth(MwWidget handle, const char* text) { ttf_t* ttf = MwGetVoid(handle, MwNfont); int ax, lsb; int tw = 0; @@ -172,26 +180,108 @@ int ttf_MwTextWidth(MwWidget handle, const char* text) { return tw; } -int ttf_MwTextHeight(MwWidget handle, int count) { +static int ttf_MwTextHeight(MwWidget handle, int count) { ttf_t* ttf = MwGetVoid(handle, MwNfont); if(ttf == NULL) return -1; return (ttf->ascent - ttf->descent) * ttf->scale * count; } +#elif defined(USE_FREETYPE2) +static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + ttf_t* ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); + int tw, th; + unsigned char* px; + MwLLPixmap p; + MwRect r; + int x = 0; + if(ttf == NULL) return 1; + + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + int c; + FT_Bitmap* bmp; + int cy, cx; + text += MwUTF8ToUTF32(text, &c); + + FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + bmp = &ttf->face->glyph->bitmap; + + for(cy = 0; cy < bmp->rows; cy++) { + for(cx = 0; cx < bmp->width; cx++) { + int ox = x + cx + ttf->face->glyph->bitmap_left; + int oy = th - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * 14 / ttf->face->units_per_EM); + unsigned char* opx = &px[(oy * tw + ox) * 4]; + + opx[0] = color->red; + opx[1] = color->green; + opx[2] = color->blue; + opx[3] = bmp->buffer[cy * bmp->pitch + cx]; + } + } + + x += ttf->face->glyph->metrics.horiAdvance / 64; + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int ttf_MwTextWidth(MwWidget handle, const char* text) { + ttf_t* ttf = MwGetVoid(handle, MwNfont); + int tw = 0; + if(ttf == NULL) return -1; + + while(text[0] != 0) { + int c; + text += MwUTF8ToUTF32(text, &c); + + FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + + tw += ttf->face->glyph->metrics.horiAdvance / 64; + } + + return tw; +} + +static int ttf_MwTextHeight(MwWidget handle, int count) { + ttf_t* ttf = MwGetVoid(handle, MwNfont); + if(ttf == NULL) return -1; + + return (ttf->face->height * 14 / ttf->face->units_per_EM) * count; +} #endif void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { -#ifdef USE_STB_TRUETYPE +#ifdef TTF if(ttf_MwDrawText(handle, point, text, bold, align, color)) #endif bitmap_MwDrawText(handle, point, text, bold, align, color); } int MwTextWidth(MwWidget handle, const char* text) { + /* TODO: check newline */ +#ifdef TTF int st; - /* TODO: check newline */ -#ifdef USE_STB_TRUETYPE if((st = ttf_MwTextWidth(handle, text)) != -1) return st; #else (void)handle; @@ -203,7 +293,9 @@ int MwTextWidth(MwWidget handle, const char* text) { int MwTextHeight(MwWidget handle, const char* text) { int c = 1; int i = 0; +#ifdef TTF int st; +#endif (void)handle; (void)text; @@ -214,14 +306,24 @@ int MwTextHeight(MwWidget handle, const char* text) { if(out == '\n') c++; } -#ifdef USE_STB_TRUETYPE +#ifdef TTF if((st = ttf_MwTextHeight(handle, c)) != -1) return st; #endif return FontHeight * c; } void* MwFontLoad(unsigned char* data, unsigned int size) { -#ifdef USE_STB_TRUETYPE +#if defined(USE_FREETYPE2) + ttf_t* ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + FT_Init_FreeType(&ttf->library); + FT_New_Memory_Face(ttf->library, ttf->data, size, 0, &ttf->face); + + FT_Set_Pixel_Sizes(ttf->face, 0, 14); + + return ttf; +#elif defined(USE_STB_TRUETYPE) ttf_t* ttf = malloc(sizeof(*ttf)); ttf->data = malloc(size); memcpy(ttf->data, data, size); @@ -232,12 +334,22 @@ void* MwFontLoad(unsigned char* data, unsigned int size) { return ttf; #else + (void)data; + (void)size; return NULL; #endif } void MwFontFree(void* handle) { -#ifdef USE_STB_TRUETYPE +#if defined(USE_FREETYPE2) + ttf_t* ttf = handle; + + FT_Done_Face(ttf->face); + FT_Done_FreeType(ttf->library); + + free(ttf->data); + free(ttf); +#elif defined(USE_STB_TRUETYPE) ttf_t* ttf = handle; free(ttf->data); diff --git a/src/text/ttf.c b/src/text/ttf.c index 3651697..3cd3073 100644 --- a/src/text/ttf.c +++ b/src/text/ttf.c @@ -1,7 +1,7 @@ /* $Id$ */ #include -#ifdef USE_STB_TRUETYPE +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) unsigned char MwTTFData[] = { 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x10, 0x46, 0x46, 0x54, 0x4d, 0xab, 0xe1, 0x51, 0x56, 0x00, 0x00, 0x55, 0xe8, diff --git a/tools/ttf.sh b/tools/ttf.sh index bdf14c3..ee11c18 100755 --- a/tools/ttf.sh +++ b/tools/ttf.sh @@ -5,7 +5,7 @@ for out in src/text/ttf.c src/text/boldttf.c; do echo '/* $Id$ */' > $out echo '#include ' >> $out echo '' >> $out - echo '#ifdef USE_STB_TRUETYPE' >> $out + echo '#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2)' >> $out done xxd -n MwTTFData -i resource/IBMPlexMono.ttf | sed s/_len/Size/ >> src/text/ttf.c xxd -n MwBoldTTFData -i resource/IBMPlexMono-Bold.ttf | sed s/_len/Size/ >> src/text/boldttf.c