diff options
| author | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-07 18:38:05 +0200 |
|---|---|---|
| committer | Jean-Philippe Bruyère <jp_bruyere@hotmail.com> | 2026-10-07 18:38:05 +0200 |
| commit | 1d1d49ea314f2e5a644b1ed9ac4908234a02e3de (patch) | |
| tree | 767a98b25aca1e97b59bb243a4558b6e0063dd52 | |
| parent | a49732e00946dc22018ff11c19eb6ee0b109b547 (diff) | |
debug wip, still queryHash sigsev remaining
| -rw-r--r-- | include/vkvg.h | 8 | ||||
| -rw-r--r-- | src/vkvg_fonts.c | 88 | ||||
| -rw-r--r-- | src/vkvg_fonts.h | 1 | ||||
| -rw-r--r-- | src/vkvg_internal.h | 1 | ||||
| -rw-r--r-- | tests/fonts/allfont.c | 326 |
5 files changed, 409 insertions, 15 deletions
diff --git a/include/vkvg.h b/include/vkvg.h index c55a9ad..8ad8d0c 100644 --- a/include/vkvg.h +++ b/include/vkvg.h @@ -340,8 +340,14 @@ typedef struct _vkvg_text_run_t* VkvgText; * */ typedef struct _vkvg_font_t* VkvgFont; - +/* + * @brief Create a new VkvgFont. + */ vkvg_public VkvgFont vkvg_font_create (VkvgDevice dev, const char* queryString, float pointSize); +/* + * @brief Get underlying font face object pointer, if freetype is enable, the FT_Face will be returned. + */ +vkvg_public void* vkvg_font_get_face (VkvgFont font); vkvg_public VkvgFont vkvg_font_reference (VkvgFont font); vkvg_public uint32_t vkvg_font_get_reference_count (VkvgFont font); vkvg_public vkvg_status_t vkvg_font_status (VkvgFont font); diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index e8df2cc..7d619b1 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -224,16 +224,12 @@ void _flush_chars_to_tex(VkvgDevice dev, vkvg_font_t* f) { _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); f->penX += cache->stagingX; - //f->texLines.elements[f->texLines.count - 1] = l; - cache->stagingX = 0; memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); } /// Start a new line in font cache, increase texture layer count if needed. void _init_next_line_in_tex_cache(VkvgDevice dev, vkvg_font_t* f) { _font_cache_t* cache = dev->fontCache; - //TexRef l = f->texLines.elements[f->texLines.count - 1]; - for (int i = 0; i < cache->texPages.count; ++i) { tex_page_t* page = &cache->texPages.elements[i]; @@ -245,6 +241,7 @@ void _init_next_line_in_tex_cache(VkvgDevice dev, vkvg_font_t* f) { TexRef lp = page->lines.elements[j]; lp->released = false; array_add_TexRef(&f->texLines, lp); + f->penX = 0; return; } } @@ -355,8 +352,11 @@ char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) { FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); #else - FT_CHECK_RESULT(FT_Load_Glyph(f->face->face, gindex, FT_LOAD_RENDER)); - + FT_Error res = FT_Load_Glyph(f->face->face, gindex, FT_LOAD_RENDER); + if (res) { + LOG(VKVG_LOG_ERR, "FT_Load_Glyph error 0x%x for glyph index %d\n", res, gindex); + FT_Load_Glyph(f->face->face, 0, FT_LOAD_RENDER); + } #endif FT_GlyphSlot slot = f->face->face->glyph; @@ -383,7 +383,7 @@ char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) { _init_next_line_in_tex_cache(dev, f); } //cr.texRefIdx = f->texLines.count - 1; - char_ref cr = {f->texLines.elements[f->texLines.count - 1], slot->glyph_index}; + char_ref cr = {f->texLines.elements[f->texLines.count - 1]}; int penX = dev->fontCache->stagingX; #ifdef VKVG_USE_FREETYPE @@ -426,7 +426,6 @@ char_ref _prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) { return cr; } - /*void _fcpattern_append(FcPattern* dest, const FcPattern* src) { FcPatternIter iter; FcPatternIterStart(src, &iter); @@ -511,7 +510,6 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F if (tryGetFontFaceFromQueryHash(cache, queryHash, face)) return true; - char *fontFile = NULL; FcPattern* request = FcNameParse((const FcChar8*)fontString); @@ -557,6 +555,7 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F unsigned long readBytes = fread(buffPtr->buffer, 1, buffPtr->bufferSize, file); fclose(file); if (readBytes != buffPtr->bufferSize) { + LOG(VKVG_LOG_ERR, "Error reading font file: %s\n", fontFile); return false; } @@ -573,6 +572,10 @@ bool _tryResolveFontNameWithFontConfig(VkvgDevice dev, const char* fontString, F mtx_init(&newFace->mutex, mtx_plain); #ifdef VKVG_USE_FREETYPE + if (cache->fontBuffers.count > 654 && cache->fontBuffers.elements[654] == buffPtr) { + printf("test\n"); + } + FT_Error res = FT_New_Memory_Face(cache->library, buffPtr->buffer, buffPtr->bufferSize, index, &newFace->face); if (res) { LOG(VKVG_LOG_ERR, "FreeType error 0x%x creating memory face in %s at line %d\n", res, __FILE__, __LINE__); @@ -781,7 +784,7 @@ void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) { char_ref cr = tr->font->charLookup[glyph_info[i].codepoint]; #ifdef VKVG_USE_HARFBUZZ - if (!cr.index) + if (!cr.texRef) cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint); #endif @@ -900,6 +903,58 @@ void _clear_cache() { } +void* vkvg_font_get_face(VkvgFont font) { + return font->face->face; +} +#ifdef VKVG_USE_FREETYPE +#define CHECK_FACE_FLAG(flags, flag, buffer) \ +do { \ + if ((flags) & (flag)) { \ + if (buffer[0] != '\0') strcat(buffer, " | "); \ + strcat(buffer, #flag); \ + } \ +} while (0) + + /** + * Converts face_flags bitmask to a human-readable string. + * Make sure the output buffer is large enough (e.g., 512 bytes). + */ +void ft_face_flags_to_string(FT_Long face_flags, char* out_str, size_t max_len) { + if (!out_str || max_len == 0) return; + out_str[0] = '\0'; + + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_SCALABLE, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_FIXED_SIZES, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_FIXED_WIDTH, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_SFNT, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_HORIZONTAL, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_VERTICAL, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_KERNING, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_MULTIPLE_MASTERS, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_GLYPH_NAMES, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_EXTERNAL_STREAM, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_HINTER, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_CID_KEYED, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_TRICKY, out_str); + CHECK_FACE_FLAG(face_flags, FT_FACE_FLAG_COLOR, out_str); + + if (out_str[0] == '\0') { + strncpy(out_str, "NONE", max_len); + } +} +#define FT_CHECK_RES(f) \ +{ \ + FT_Error res = (f); \ + if (res) { \ + char tmp[1024]; \ + ft_face_flags_to_string (face->face->face_flags, tmp, 1024); \ + LOG(VKVG_LOG_ERR, "FreeType error is 0x%x in %s at line %d, flags: %s\n", res, __FILE__, __LINE__, tmp);\ + free(font); \ + return (VkvgFont)&_vkvg_status_null_pointer; \ + } \ +} +#endif + VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) { uint32_t pt26_6 = (uint32_t)(pointSize * 64.f); VkvgFont font = NULL; @@ -922,14 +977,21 @@ VkvgFont vkvg_font_create (VkvgDevice dev, const char* query, float pointSize) { font->face = face; #ifdef VKVG_USE_FREETYPE + if (!(face->face->face_flags & (FT_FACE_FLAG_SCALABLE | FT_FACE_FLAG_SFNT))) { + char tmp[1024]; + ft_face_flags_to_string (face->face->face_flags, tmp, 1024); + LOG(VKVG_LOG_ERR, "Unsuported font flags: %s\n", tmp); + free(font); + return (VkvgFont)&_vkvg_status_null_pointer; + } if (!face->sizes.size) face->sizes = array_create_VkvgFont(5);//new face, - FT_CHECK_RESULT(FT_New_Size (face->face, &font->ftSize)); - FT_Activate_Size(font->ftSize); + FT_CHECK_RES(FT_New_Size (face->face, &font->ftSize)); + FT_CHECK_RES(FT_Activate_Size(font->ftSize)); font->eltIndex = array_add_VkvgFont(&face->sizes, font); - FT_CHECK_RESULT(FT_Set_Char_Size(face->face, 0, font->charSize, dev->hdpi, dev->vdpi)); + FT_CHECK_RES(FT_Set_Char_Size(face->face, 0, font->charSize, dev->hdpi, dev->vdpi)); font->ftSize = face->face->size; font->charLookup = (char_ref*)calloc(face->face->num_glyphs, sizeof(char_ref)); diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index a643609..85bb3bc 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -149,7 +149,6 @@ typedef struct _tex_ref_t* TexRef; // texture coordinates of one character in font cache array texture. typedef struct _char_ref { TexRef texRef; /* glyph bitmap ref */ - uint32_t index; /* stored here only to detect empty char_ref */ vec2i16 bmpDiff; /* Difference in pixel between char bitmap top left corner and char glyph*/ vec4 bounds; /* normalized float bounds of character bitmap in font cache texture. */ #ifdef VKVG_USE_FREETYPE diff --git a/src/vkvg_internal.h b/src/vkvg_internal.h index 9683317..3e7c7ca 100644 --- a/src/vkvg_internal.h +++ b/src/vkvg_internal.h @@ -163,6 +163,7 @@ static type* array_last_##type (array_##type* arr) { \ } \ static void array_destroy_##type (array_##type* arr) { \ free(arr->elements); \ + arr->elements = NULL; \ arr->count = 0; \ arr->size = 0; \ } \ diff --git a/tests/fonts/allfont.c b/tests/fonts/allfont.c new file mode 100644 index 0000000..747b068 --- /dev/null +++ b/tests/fonts/allfont.c @@ -0,0 +1,326 @@ +#include "test.h" +#include <fontconfig/fontconfig.h> +#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 + +float fontSize = 16.0f; +int curFontStartIdx = 0; +bool redraw = true; + +#define MAX_STRING_LEN 1024 + +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", "เป็นมนุษย์สุดประเสริฐเลิศคุณค่า" }, // 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) +}; + +void get_sample_by_fc_lang(const char* fc_lang, char* str) { + const char* sample = NULL; + if (fc_lang) { + for (int i = 1; i < 38; 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; + printf("missing lang sample: %s\n", fc_lang); + } + } + + // Check if the fontconfig language string starts with a known code + strncpy(str, sample, strlen(sample)+1); +} + + +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) + return false; + + lang = FcStrListNext(lang_list); + + if (!lang) + return false; + //printf("lang: %s\n", str); + get_sample_by_fc_lang((char*)lang, str); + + FcStrListDone(lang_list); + return true; + } + return false; +} + + +void draw(VkvgSurface surfFont) { + if (!font_database) + return; + VkvgContext ctx = vkvg_create(surfFont); + vkvg_clear(ctx); + vkvg_set_source_rgb(ctx,1,1,1); + + float penX = 10.f; + float penY = 50.f; + + char tmp[1024]; + + for (int i = curFontStartIdx; i < font_database->nfont; i++) { + FcPattern* font_entry = font_database->fonts[i]; + + FcChar8* family_name = NULL; + FcChar8* style_variant = NULL; + FcChar8* file_path = NULL; + + if (FcPatternGetString(font_entry, FC_FAMILY, 0, &family_name) == FcResultMatch && + FcPatternGetString(font_entry, FC_STYLE, 0, &style_variant) == FcResultMatch) { + + FcPatternGetString(font_entry, FC_FILE, 0, &file_path); + sprintf(tmp, "%s", family_name); + + + VkvgFont font = vkvg_font_create (device, tmp, fontSize); + if (vkvg_font_status(font)) { + printf("Error trying to load %s, from %s\n", tmp, file_path); + fflush(stdout); + continue; + } + vkvg_set_font (ctx, font); + vkvg_move_to (ctx, penX, penY); + + FT_Face face = (FT_Face)vkvg_font_get_face(font); + if (!try_get_sample_string(font_entry, face, tmp)) + sprintf(tmp, "%s : %s", family_name, style_variant); + + vkvg_show_text (ctx,tmp); + vkvg_flush(ctx); + vkvg_font_destroy(font); + + penY += fontSize * 1.5f; + } + if (penY > test_height - 100) + break; + tmp[0] = '\0'; + } + + vkvg_destroy(ctx); +} +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; + } + redraw = true; +} +static void mouse_move_callback(GLFWwindow* window, double x, double y) { +} +static void scroll_callback(GLFWwindow* window, double x, double y) { + if (y > 0.f) { + if (curFontStartIdx > 0) + curFontStartIdx --; + } else if (font_database) { + if (curFontStartIdx < font_database->nfont) + curFontStartIdx ++; + } + 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 = VKVG_LOG_ERR; + + _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); + + vkvg_device_create_info_t info = { + 4, 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); + + if (!FcInit()) { + fprintf(stderr, "Fatal Error: Failed to initialize Fontconfig.\n"); + return -1; + } + FcConfig* config = FcConfigGetCurrent(); + FcPattern* blank_pattern = FcPatternCreate(); + FcObjectSet* requested_elements = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, FC_LANG, (char *)0); + font_database = FcFontList(config, blank_pattern, requested_elements); + + 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_device_destroy(device); + + vkengine_destroy(e); + + FcFontSetDestroy(font_database); + FcObjectSetDestroy(requested_elements); + FcPatternDestroy(blank_pattern); + FcFini(); + + return 0; +} |