diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-10 17:27:23 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-10 17:27:23 +0200 |
| commit | b4babe4eab5bf39191e435e288edd78cff3c233b (patch) | |
| tree | 56ae40b587730050329a525c57fe777b07be776d | |
| parent | d13fdbbfc6ec430333e517b9646efa47b911c2b8 (diff) | |
update stbtt
| -rw-r--r-- | src/vkvg_context.c | 2 | ||||
| -rw-r--r-- | src/vkvg_fonts.c | 33 | ||||
| -rw-r--r-- | tests/fonts/allfont.c | 21 | ||||
| -rw-r--r-- | tests/fonts/fontquery.c | 457 |
4 files changed, 489 insertions, 24 deletions
diff --git a/src/vkvg_context.c b/src/vkvg_context.c index 29e9a6a..5893c82 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -1188,7 +1188,7 @@ void vkvg_select_font_face(VkvgContext ctx, const char* name) { if (vkvg_status(ctx)) return; RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name); - _select_font_face(ctx, name); + vkvg_set_font(ctx, vkvg_font_create(ctx->dev, name, 12)); } void vkvg_load_font_from_path(VkvgContext ctx, const char* path, const char* name) { if (vkvg_status(ctx)) diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 01d9c20..342654c 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -474,7 +474,6 @@ vkvg_inline glyph_ref get_cached_glyph (VkvgDevice dev, VkvgFont font, uint32_t return font->charLookup[gIndex]; } - bool try_get_font_face_from_query_hash(_font_cache_t* cache, uint64_t queryHash, FontFace *const face) { *face = NULL; FontBuffer* buffs = cache->fontBuffers.elements; @@ -567,8 +566,8 @@ bool try_create_font_face_from_path (VkvgDevice dev, const char *fontFile, int f #endif #else int font_count = stbtt_GetNumberOfFonts(buffPtr->buffer); - int offset = stbtt_GetFontOffsetForIndex(buffPtr->buffer, faceIndex); - int result = stbtt_InitFont(&newFace->stbInfo, buffPtr->buffer, offset); + int offset = stbtt_GetFontOffsetForIndex(buffPtr->buffer, faceIndex & 0xFFFF);//variable font not handled by stbtt + int result = stbtt_InitFont(&newFace->stbInfo, buffPtr->buffer, offset < 0 ? 0 : offset); if (!result) { LOGE("stbtt_InitFont error 0x%x creating face in %s at line %d\n", result, __FILE__, __LINE__); return false; @@ -662,8 +661,6 @@ void _font_lock_size (VkvgContext ctx, VkvgFont font) { // retrieve global font extends of context's current font as defined by FreeType void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) { - - // TODO: ensure correct metrics are returned (scalled/unscalled, etc..) VkvgFont font = ctx->currentFont; #ifdef VKVG_USE_FREETYPE FT_Face face = font->face->face; @@ -687,10 +684,9 @@ void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t* extents) { /*if (ctx->dev->threadAware) mtx_unlock(&font->face->mutex);*/ #else - extents->ascent = roundf(font->scale * ctx->currentFont->ascent); - extents->descent = -roundf(font->scale * ctx->currentFont->descent); - extents->height = - roundf(font->scale * (ctx->currentFont->ascent - ctx->currentFont->descent + ctx->currentFont->lineGap)); + extents->ascent = font->ascent; + extents->descent = font->descent; + extents->height = font->ascent - font->descent + font->lineGap; extents->max_x_advance = 0; // TODO extents->max_y_advance = 0; #endif @@ -748,16 +744,14 @@ void text_run_init(VkvgContext ctx, const char* text, int length, VkvgText textR textRun->glyphs = (vkvg_glyph_info_t*)malloc(textRun->glyph_count * sizeof(vkvg_glyph_info_t)); for (unsigned int i = 0; i < textRun->glyph_count; i++) { #ifdef VKVG_USE_FREETYPE - uint32_t gindex = FT_Get_Char_Index(textRun->font->face, tmp[i]); + uint32_t gIndex = FT_Get_Char_Index(textRun->font->face->face, tmp[i]); #else - uint32_t gindex = stbtt_FindGlyphIndex(&textRun->fontId->stbInfo, tmp[i]); + uint32_t gIndex = stbtt_FindGlyphIndex(&textRun->font->face->stbInfo, tmp[i]); #endif - _char_ref* cr = textRun->font->charLookup[gindex]; - if (cr == NULL) - cr = _prepare_char(textRun->dev, textRun, gindex); - textRun->glyphs[i].codepoint = gindex; - textRun->glyphs[i].x_advance = cr->advance.x; - textRun->glyphs[i].y_advance = cr->advance.y; + glyph_ref cr = get_cached_glyph(textRun->dev, textRun->font, gIndex); + textRun->glyphs[i].codepoint = gIndex; + textRun->glyphs[i].x_advance = cr.advance.x; + textRun->glyphs[i].y_advance = cr.advance.y; textRun->glyphs[i].x_offset = 0; textRun->glyphs[i].y_offset = 0; /*textRun->glyphs[i].x_offset = cr->bmpDiff.x; @@ -1010,7 +1004,6 @@ VkvgFont vkvg_font_create_from_file (VkvgDevice dev, const char* fontFilePath, i } return _create_font_from_face(dev, face, pointSize); } - VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) { uint32_t pt26_6 = (uint32_t)(pointSize * 64.f); @@ -1027,8 +1020,6 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) { return _create_font_from_face(dev, face, pointSize); } - - VkvgFont vkvg_font_reference(VkvgFont font) { if (!vkvg_font_status(font)) atomic_fetch_add_explicit(&font->references, 1, memory_order_relaxed); @@ -1040,9 +1031,7 @@ uint32_t vkvg_font_get_reference_count(VkvgFont font) { return 0; return atomic_load_explicit(&font->references, memory_order_relaxed); } - vkvg_status_t vkvg_font_status(VkvgFont font) { return !font ? VKVG_STATUS_NULL_POINTER : font->status; } - void vkvg_font_destroy(VkvgFont font) { if (vkvg_font_status(font)) return; diff --git a/tests/fonts/allfont.c b/tests/fonts/allfont.c index efafa8a..e9f94a9 100644 --- a/tests/fonts/allfont.c +++ b/tests/fonts/allfont.c @@ -1,5 +1,7 @@ #include "test.h" +#ifdef VKVG_USE_FONTCONFIG #include <fontconfig/fontconfig.h> +#endif #ifdef VKVG_USE_FREETYPE #include <ft2build.h> @@ -18,6 +20,7 @@ bool redraw = true; #define MAX_STRING_LEN 1024 +#ifdef VKVG_USE_FONTCONFIG FcFontSet* font_database = NULL; typedef struct { @@ -247,6 +250,14 @@ void draw(VkvgSurface surfFont) { vkvg_destroy(ctx); } +#else +void draw(VkvgSurface surfFont) { + VkvgContext ctx = vkvg_create(surfFont); + vkvg_clear(ctx); + vkvg_destroy(ctx); +} +#endif + static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_RELEASE) return; @@ -267,6 +278,8 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, static void mouse_move_callback(GLFWwindow* window, double x, double y) { } static void scroll_callback(GLFWwindow* window, double x, double y) { +#ifdef VKVG_USE_FONTCONFIG + const int step = 5; if (y > 0.f) { if (curFontStartIdx > 0) @@ -276,6 +289,7 @@ static void scroll_callback(GLFWwindow* window, double x, double y) { if (curFontStartIdx < font_database->nfont) curFontStartIdx +=5; } +#endif redraw = true; } static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif) { @@ -290,7 +304,7 @@ static void mouse_button_callback(GLFWwindow* window, int but, int state, int mo int main(int argc, char* argv[]) { vkh_log_level = VKH_LOG_FULL; - vkvg_log_level = VKVG_LOG_ERR | VKVG_LOG_WARN | VKVG_LOG_FONT; + vkvg_log_level = VKVG_LOG_ERR | VKVG_LOG_WARN | VKVG_LOG_FONT ; _parse_args(argc, argv); VkEngine e = vkengine_create ( @@ -315,6 +329,8 @@ int main(int argc, char* argv[]) { vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); +#ifdef VKVG_USE_FONTCONFIG + if (!FcInit()) { fprintf(stderr, "Fatal Error: Failed to initialize Fontconfig.\n"); return -1; @@ -326,6 +342,7 @@ int main(int argc, char* argv[]) { FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); font_database = FcFontList(config, request, requested_elements); +#endif while (!vkengine_should_close(e)) { glfwPollEvents(); @@ -361,10 +378,12 @@ int main(int argc, char* argv[]) { vkengine_destroy(e); +#ifdef VKVG_USE_FONTCONFIG FcFontSetDestroy(font_database); FcObjectSetDestroy(requested_elements); FcPatternDestroy(request); FcFini(); +#endif return 0; } diff --git a/tests/fonts/fontquery.c b/tests/fonts/fontquery.c new file mode 100644 index 0000000..37b8a92 --- /dev/null +++ b/tests/fonts/fontquery.c @@ -0,0 +1,457 @@ +#include "test.h" +#ifdef VKVG_USE_FONTCONFIG +#include <fontconfig/fontconfig.h> +#endif + +#ifdef VKVG_USE_FREETYPE +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_SFNT_NAMES_H +#include FT_TRUETYPE_TABLES_H +#include FT_TRUETYPE_IDS_H +#include FT_MULTIPLE_MASTERS_H +#endif + +#include <string.h> + +float fontSize = 28.0f; +int curFontStartIdx = 0; +bool redraw = true; + +#define MAX_STRING_LEN 1024 + +FcConfig* config = NULL; +FcFontSet* font_database = NULL; + +typedef struct { + const char* lang_code; + const char* sample_text; +} LocaleSample; + +// A localized library of pan-unicode text variations +static const LocaleSample script_samples[] = { + { "en", "The quick brown fox jumps over the lazy dog." }, // Latin Fallback + { "ja", "いろはにほへと ちりぬるを わかよたれそ つねならむ" }, // Japanese Hiragana + { "zh", "天地玄黃,宇宙洪荒。日月盈昃,辰宿列張。" }, // Chinese Hanzi + { "ko", "다람쥐 쳇바퀴에 타고파" }, // Korean Hangul + { "ru", "Съешь же ещё этих мягких французских булок, да выпей чаю" }, // Cyrillic + { "ar", "نص حكيم له سر قاطع وذو شأن عظيم ينقص" }, // Arabic + { "he", "דג אכל גזר באשחט" }, // Hebrew + { "hi", "ऋषियों को तपस्या करते देख, दुष्टों के मन में डर पैदा हुआ।" }, // Hindi / Devanagari + { "el", "διαφυλάξτε γενικά τη ζωή σας από τον φόβο" }, // Greek + { "th", "เป็นมนุษย์สุดประเสริฐเลิIศคุณค่า" }, // Thai + { "hy", "Ֆիզիկոս Մկրտիչը օճառաջուր ցողելով բժշկում է գնդապետ Հայկի փքված ձախ թևը։" }, // Armenian + { "agr", "Agatjai juuk tusha numpanum ijuaku jintanum pujawai" }, // Aguaruna (Latin script variation) + //{ "aa", "Afari fanta asat darih doro dahanik xisbisa" }, // Afar (Latin script variation) + { "bem", "Abantu bonse bafyalwa abalubuka no kulingana mu mucinshi" }, // Bemba (Bantu Latin script) + { "pa", "ਘੁਮਿਆਰ ਨੇ ਮਿੱਟੀ ਚੁੱਕ ਕੇ ਇੱਕ ਬਹੁਤ ਹੀ ਸੁੰਦਰ ਘੜਾ ਬਣਾਇਆ।" }, // Punjabi (Gurmukhi script) + { "te", "కచ్ఛపము మందగమనముతో చెరువు వైపు వెళుతోంది." }, // Telugu (Telugu script) + { "km", "ខ្យល់បក់បោកបបួលបក្សីហើរទៅកាន់ព្រៃព្រឹក្សាដ៏ស្ងប់ស្ងាត់។" }, // Khmer (Khmer script) + { "lo", "ນົກກາງແກບິນຂ້າມທົ່ງນາທີ່ກວ້າງໃຫຍ່ໄພສານຢ່າງສະຫງ່າງາມ." }, // Lao (Lao script) + { "ta", "தமிழ் மொழி உலகினில் மிக தொன்மையான மற்றும் அழகான மொழியாகும்." }, // Tamil (Tamil script) + { "or", "ଋଷିମାନେ ଅରଣ୍ୟ ମଧ୍ୟରେ ଧ୍ୟାନ କରି ଶାନ୍ତି ଲାଭ କରନ୍ତି।" }, // Odia/Oriya (Odia script) + { "ml", "ഭൂമിയിലെ എല്ലാ മനുഷ്യരും തുല്യ അവകാശങ്ങളോടെ ജനിക്കുന്നു." }, // Malayalam (Malayalam script) + { "as", "শৰৎকালৰ স্নিগ্ধ জোনাক ৰাতি আকাশখন বৰ ধুনীয়া দেখায়।" }, // Assamese (Bengali-Assamese script) + { "si", "සියලු මනුෂ්යයෝ නිදහස්ව උපත ලබා ඇත." }, // Sinhala (Sinhala script) + { "am", "የሰው ልጅ ሁሉ ሲወለድ ነጻና በክብርም በሕግም እኩል ነው።" }, // Amharic (Ge'ez/Ethiopic script) + { "anp", "सभ्भे मानुस जनम सँ सुतन्तर आरो अधिकार में बराबर छै।" }, // Angika (Devanagari variant) + { "kn", "ಎಲ್ಲಾ ಮಾನವರು ಸ್ವತಂತ್ರರಾಗಿಯೇ ಜನಿಸಿದ್ದಾರೆ." }, // Kannada (Kannada script) + { "gu", "બધા મનુષ્યો ગૌરવ અને અધિકારોની બાબતમાં સમાન છે." }, // Gujarati (Gujarati script) + { "bo", "འགྲོ་བ་མི་ཉིད་མ་སྐྱེས་པ་ནས་བཟུང་རང་དབང་ཡིན།" }, // Tibetan (Tibetan script) + { "ka", "ადამიანი იბადება თავისუფალი და თანასწორი." }, // Georgian (Mkhedruli script) + { "mnw", "မန်ဝံသဂမၠိုၚ် က္တဵုဒှ်ကၠုၚ် နကဵုဂုဏ်သိက္ခာ ညဳသၟဟ်ဂမၠိုၚ်။" }, // Mon (Mon-Burmese script) + { "ii", "ꊿꊪꉼꆹꊪꊪꊿꐊꐥꌋꅍꐛꐹꂿꆪꄮꄯꉼꆹꄮꄯꂿꆪꊨꏦꍏꆪꐥꌋꅍꐛꐹꏦꍏꅪꏦꍏꅪꐨꏦꍏꄮꄯꅪ" }, // Nuosu / Liangshan Yi (Yi syllabary) + { "chr", "ᏂᎦᏛ ᎠᏂᏰᎸᎢ ᎤᏂᎲᏓ ᏂᎨᏒᎾ ᎤᎾᏕᎲᎩ ᎢᏳᏍᏗᏉ ᎨᏒ ᎦᎸᏉᏗᏳ" }, // Cherokee (Cherokee syllabary) + { "ber-ma", "ⵎⴰⵕⵕⴰ ⵉⵎᏓⵏⵏ ⴷⴳ ⵓⵍⵉⴼ ⴷ ⵉⵣⵔⴼⴰⵏ ⴷ ⵍⵃⵇⵇ ⵜⵜⵍⴰⵍⴰⵏ ⴷ ⵉⵍⴻⵍⵍⵉⵢⵏ." }, // Moroccan Berber (Tifinagh script) + { "ab", "Дарбанზаалак ауаҩы дшоуп ихы ақәgenericуи иҳаgenericти." }, // Abkhaz (Cyrillic variation) + { "syr", "ܟܠ ܒܪܢܫܐ ܡܬܝܠܕ ܚܐܪܐ ܘܫܘܝܐ ܒܐܝܩܪܐ ܘܒܙܕܩܐ." }, // Syriac (Syriac script, right-to-left) + { "iu", "ᐃᓅᔪᓕᒫᑦ ᐊᓂᖅᑎᕆᔪᓕᒫᑦ ᐃᓅᕗᑦ ᐃᓱᒪᕐᓱᕐᖢᑎᒃ ᐊᒻᒪ ᐊᔾᔨᒌᒃᑐᒥᒃ" }, // Inuktitut (Canadian Aboriginal Syllabics) + { "dv", "ހުރިހާ އިންސާނުންވެސް އުފަންވަނީ މިނިވަންކަމާއި ޢިއްޒަތާއި" }, // Dhivehi / Maldivian (Thaana script, right-to-left) + { "mn-cn", "Хүн бүр төрөхDiscussion эрх чөлөөтэй, нэр төр, эрхийн хувьд адилхан." }, // Mongolian - Inner Mongolia (Cyrillic fallback) +}; + +bool try_get_sample_by_fc_lang(const char* fc_lang, char* str) { + const char* sample = NULL; + if (fc_lang) { + for (int i = 1; i < 37; i++) { + if (strncmp(fc_lang, script_samples[i].lang_code, strlen(script_samples[i].lang_code)) == 0) { + sample = script_samples[i].sample_text; + break; + } + } + if (!sample) { + sample = script_samples[0].sample_text; + return false; + } + } + + strncpy(str, sample, strlen(sample)+1); + return true; +} + +#ifdef VKVG_USE_FREETYPE +void convert_utf16be_to_utf8(const FT_Byte* src, FT_UInt src_len, char* dest, FT_UInt dest_max_len) { + FT_UInt d_idx = 0; + + // Iterate 2 bytes at a time for UTF-16 + for (FT_UInt s_idx = 0; s_idx < src_len && d_idx < (dest_max_len - 4); s_idx += 2) { + // Reconstruct the 16-bit Unicode Code Point (Big Endian) + unsigned short cp = (src[s_idx] << 8) | src[s_idx + 1]; + + // 1-byte UTF-8 (Standard ASCII Range) + if (cp < 0x80) { + dest[d_idx++] = (char)cp; + } + // 2-byte UTF-8 (Cyrillic, Hebrew, Arabic, etc.) + else if (cp < 0x800) { + dest[d_idx++] = (char)(0xC0 | (cp >> 6)); + dest[d_idx++] = (char)(0x80 | (cp & 0x3F)); + } + // 3-byte UTF-8 (Chinese, Japanese, Devanagari, Hangul, etc.) + else { + dest[d_idx++] = (char)(0xE0 | (cp >> 12)); + dest[d_idx++] = (char)(0x80 | ((cp >> 6) & 0x3F)); + dest[d_idx++] = (char)(0x80 | (cp & 0x3F)); + } + } + dest[d_idx] = '\0'; // Properly null-terminate +} + +bool try_get_sample_string(FcPattern* font_entry, FT_Face face, char* str) { + // Check if the font has an SFNT name table (TrueType/OpenType files) + if (!FT_IS_SFNT(face)) { + return false; + } + + FT_UInt count = FT_Get_Sfnt_Name_Count(face); + FT_SfntName name_rec; + + for (FT_UInt i = 0; i < count; i++) { + if (FT_Get_Sfnt_Name(face, i, &name_rec) == 0) { + // 19 is the pre-defined ID for "Sample text" + if (name_rec.name_id == 19) { + if (name_rec.platform_id == 3 || name_rec.platform_id == 0) { + convert_utf16be_to_utf8(name_rec.string, name_rec.string_len, str, MAX_STRING_LEN); + } else { + memcpy(str, name_rec.string, name_rec.string_len); + str[name_rec.string_len] = '\0'; + } + + return true; + } + } + } + FcLangSet* langset = NULL; + FcChar8* lang = NULL; + if (FcPatternGetLangSet(font_entry, FC_LANG, 0, &langset) == FcResultMatch) { + FcStrSet *lang_set = FcLangSetGetLangs(langset); + if (!lang_set) + return false; + FcStrList *lang_list = FcStrListCreate(lang_set); + if (!lang_list) { + FcStrListDone(lang_list); + return false; + } + + while ((lang = FcStrListNext(lang_list))) { + if (!lang) + continue; + if (try_get_sample_by_fc_lang((char*)lang, str)) + break; + } + + FcStrListDone(lang_list); + FcStrSetDestroy(lang_set); + return true; + } + return false; +} +#endif + +#define MAX_TXT_LEN 1024 +VkvgFont sans16 = NULL; +char txtBuffer[MAX_TXT_LEN]; +int txtBuffPtr = 0; + +float uiFontSize = 18.f; + +void draw(VkvgSurface surfFont) { + if (!font_database) + return; + VkvgContext ctx = vkvg_create(surfFont); + vkvg_clear(ctx); + + float xQ = 10; + float yQ = 20; + + vkvg_set_font(ctx,sans16); + vkvg_set_source_rgb(ctx,1,1,1); + + vkvg_font_extents_t fe = {0}; + vkvg_font_extents(ctx, &fe); + + vkvg_rectangle(ctx, xQ-2, yQ - fe.ascent, fe.max_x_advance + MAX_TXT_LEN + 4, fe.height); + vkvg_set_line_width(ctx, 1); + vkvg_stroke(ctx); + + vkvg_move_to(ctx, xQ, yQ); + vkvg_show_text(ctx, txtBuffer); + + char tmp[1024]; + strcpy(tmp,txtBuffer); + + FcPattern* request = FcPatternCreate(); + FcObjectSet* requested_elements = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, FC_LANG, (char *)0); + + char *style = strstr(tmp, ":"); + if (style) { + *style='\0'; + style++; + if (strlen(style) > 0) { + FcPatternAddString(request, FC_STYLE, (const FcChar8 *)style); + } else { + style = NULL; + } + } + FcPatternAddString(request, FC_FAMILY, (const FcChar8 *)tmp); + FcPatternAddBool(request, FC_SCALABLE, FcTrue); + FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); + + //FcConfigSubstitute(config, request, FcMatchPattern); + //FcDefaultSubstitute(request); + + FcFontSet* fonts = FcFontList(config, request, requested_elements); + + FcChar8* family_name = NULL; + FcChar8* style_variant = NULL; + FcChar8* fontFile = NULL; + int index = 0; + + float penX = 10; + float penY = 50; + + FcPattern* font = NULL; + if (fonts && fonts->nfont == 1) { + font = fonts->fonts[0]; + + FcPatternGetString (font, FC_FILE, 0, &fontFile); + FcPatternGetInteger (font, FC_INDEX, 0, &index); + FcPatternGetString (font, FC_FAMILY, 0, &family_name); + FcPatternGetString (font, FC_STYLE, 0, &style_variant); + VkvgFont f = vkvg_font_create_from_file(device, (char*)fontFile, index, fontSize); + if (vkvg_font_status(f)) { + printf("Error trying to load %s, from %s\n", tmp, fontFile); + fflush(stdout); + goto clean_exit; + } + vkvg_set_font (ctx, f); + + penX = 200; + penY = 200; + sprintf(tmp, "%s : %s", family_name, style_variant); + + vkvg_font_extents_t fe = {0}; + vkvg_font_extents(ctx, &fe); + VkvgText tr = vkvg_text_run_create(ctx, tmp); + vkvg_text_extents_t extents = {0}; + vkvg_text_run_get_extents(tr, &extents); + vkvg_rectangle(ctx, penX, penY - fe.ascent, extents.width, extents.height); + vkvg_set_line_width(ctx, 1); + vkvg_set_source_rgba(ctx,0.5f,0.5f,1, 0.7f); + vkvg_stroke(ctx); + + vkvg_move_to (ctx, penX, penY); + vkvg_set_source_rgba(ctx,1,0,0,0.5f); + vkvg_arc(ctx, penX, penY, 3, 0, 2 * M_PI); + vkvg_fill(ctx); + + vkvg_move_to (ctx, penX, penY); + vkvg_set_source_rgb(ctx,1,1,1); + vkvg_show_text_run(ctx,tr); + + vkvg_flush(ctx); + vkvg_text_run_destroy(tr); + vkvg_font_destroy(f); + } else { + for (int i = curFontStartIdx; i < font_database->nfont; i++) { + font = font_database->fonts[i]; + FcPatternGetString (font, FC_FILE, 0, &fontFile); + FcPatternGetInteger (font, FC_INDEX, 0, &index); + FcPatternGetString (font, FC_FAMILY, 0, &family_name); + FcPatternGetString (font, FC_STYLE, 0, &style_variant); + + if (family_name && strstr((char*)family_name, tmp)) { + if (!style || (style && style_variant && strstr((char*)style_variant, style))) { + sprintf(tmp, "%s:%s", family_name,style_variant); + vkvg_move_to(ctx, penX, penY); + vkvg_show_text(ctx, tmp); + penY+=fe.height; + + if (penY > test_height) + break; + } + } + + } + } +clean_exit: + FcPatternDestroy(request); + FcFontSetDestroy(fonts); + FcObjectSetDestroy(requested_elements); + + vkvg_destroy(ctx); +} + +static void char_callback(GLFWwindow *window, unsigned int codepoint) { + if (txtBuffPtr >= MAX_TXT_LEN - 1) + return; + txtBuffer[txtBuffPtr] = (char)codepoint; + txtBuffer[++txtBuffPtr] = '\0'; + redraw = true; +} +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (action == GLFW_RELEASE) + return; + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GLFW_TRUE); + break; + case GLFW_KEY_KP_ADD: + fontSize++; + break; + case GLFW_KEY_KP_SUBTRACT: + if (fontSize > 5.f) + fontSize--; + break; + case GLFW_KEY_BACKSPACE: + if (txtBuffPtr > 0) { + txtBuffPtr--; + } + txtBuffer[txtBuffPtr]='\0'; + break; + /*case GLFW_KEY_DELETE: + if (txtBuffPtr > 0 && txtBuffPtr < MAX_TXT_LEN - 2) { + memmove(&txtBuffer[txtBuffPtr], (&txtBuffer[txtBuffPtr + 1], MAX_TXT_LEN - txtB) + } + break;*/ + } + redraw = true; +} +static void mouse_move_callback(GLFWwindow* window, double x, double y) { +} +static void scroll_callback(GLFWwindow* window, double x, double y) { +#ifdef VKVG_USE_FONTCONFIG + + const int step = 5; + if (y > 0.f) { + if (curFontStartIdx > 0) + curFontStartIdx -= step; + curFontStartIdx = MAX(curFontStartIdx, 0); + } else { + curFontStartIdx +=step; + } +#endif + redraw = true; +} +static void mouse_button_callback(GLFWwindow* window, int but, int state, int modif) { + if (but != GLFW_MOUSE_BUTTON_1) + return; + if (state == GLFW_TRUE) + mouseDown = true; + else + mouseDown = false; + redraw = true; +} + +int main(int argc, char* argv[]) { + vkh_log_level = VKH_LOG_FULL; + vkvg_log_level = VKVG_LOG_ERR | VKVG_LOG_WARN | VKVG_LOG_FONT ; + + _parse_args(argc, argv); + VkEngine e = vkengine_create ( + VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, VK_PRESENT_MODE_FIFO_KHR, test_width, test_height); + + VkhPresenter r = e->renderer; + vkengine_set_key_callback(e, key_callback); + vkengine_set_mouse_but_callback(e, mouse_button_callback); + vkengine_set_cursor_pos_callback(e, mouse_move_callback); + vkengine_set_scroll_callback(e, scroll_callback); + vkengine_set_char_callback(e, char_callback); + + vkvg_device_create_info_t info = { + 1, false, + vkh_app_get_inst(e->app), + vkh_device_get_phy(e->dev), + vkh_device_get_vkdev(e->dev), + e->gQFamIdx, 0}; + + device = vkvg_device_create(&info); + surf = vkvg_surface_create(device, test_width, test_height); + VkvgSurface surfFont = vkvg_surface_create(device, test_width, test_height); + + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + +#ifdef VKVG_USE_FONTCONFIG + + if (!FcInit()) { + fprintf(stderr, "Fatal Error: Failed to initialize Fontconfig.\n"); + return -1; + } + config = FcConfigGetCurrent(); + FcPattern* request = FcPatternCreate(); + FcObjectSet* requested_elements = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, FC_LANG, (char *)0); + FcPatternAddBool(request, FC_SCALABLE, FcTrue); + FcPatternAddString(request, FC_FONTFORMAT, (const FcChar8 *)"TrueType"); + + font_database = FcFontList(config, request, requested_elements); +#endif + + strcpy (txtBuffer, "sans"); + txtBuffPtr = 4; + sans16 = vkvg_font_create(device, "sans", 16); + + while (!vkengine_should_close(e)) { + glfwPollEvents(); + + if (redraw) { + draw(surfFont); + VkvgContext ctx = vkvg_create(surf); + vkvg_clear(ctx); + vkvg_set_source_surface(ctx,surfFont,0,0); + vkvg_paint(ctx); + vkvg_destroy(ctx); + redraw = false; + } + + if (!vkh_presenter_draw(r)) { + vkh_presenter_get_size(r, &test_width, &test_height); + vkvg_surface_destroy(surf); + vkvg_surface_destroy(surfFont); + surf = vkvg_surface_create(device, test_width, test_height); + surfFont = vkvg_surface_create(device, test_width, test_height); + vkh_presenter_build_blit_cmd(r, vkvg_surface_get_vk_image(surf), test_width, test_height); + vkengine_wait_idle(e); + redraw = true; + continue; + } + } + vkengine_wait_idle(e); + + vkvg_surface_destroy(surfFont); + vkvg_surface_destroy(surf); + + vkvg_font_destroy(sans16); + + vkvg_device_destroy(device); + + vkengine_destroy(e); + +#ifdef VKVG_USE_FONTCONFIG + FcFontSetDestroy(font_database); + FcObjectSetDestroy(requested_elements); + FcPatternDestroy(request); + FcFini(); +#endif + + return 0; +} |