vurtun / nuklear

A single-header ANSI C gui library
13.69k stars 1.11k forks source link

Giant font atlas handing #738

Open YukinoHayakawa opened 6 years ago

YukinoHayakawa commented 6 years ago

The font worked well until I try to bake thousands of (Asian characters) moderately big characters (32 pixels) into the atlas. With Vulkan the texture is stretched vertically so it renders garbage. With DX11 it fails when creating the texture. Using RenderDoc I noticed that the texture is 1024*32768 in size, while my GPU has texture dimension limit of 16384. It astonished me when I found this line in the source: https://github.com/vurtun/nuklear/blob/0275cc578981ab9cebd79e4245a8322087d2b518/nuklear.h#L12688 It might be better if the user can specify the width in font config or guess from font size.

Another problem caused by this width "calculation" is that much space is wasted in the lower half of the texture. image

YukinoHayakawa commented 6 years ago

I edited the source to guess a width based on the largest font size. It works and memory utilization seems better but still might not suit general cases (and it uses ceil from std lib). Better ideas?

int max_size = 0;
if (!image_memory || !width || !height || !config_list || !count) return nk_false;
for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
    it = config_iter;
    do {range_count = nk_range_count(it->range);
        total_range_count += range_count;
        total_glyph_count += nk_range_glyph_count(it->range, range_count);
        if(it->size > max_size)
            max_size = (int)ceil(it->size);
    } while ((it = it->n) != config_iter);
}
/* setup font baker from temporary memory */
for (config_iter = config_list; config_iter; config_iter = config_iter->next) {
    it = config_iter;
    do {if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)it->ttf_blob, 0))
        return nk_false;
    } while ((it = it->n) != config_iter);
}
*height = 0;
*width = nk_round_up_pow2((int)sqrt(max_size * max_size * total_glyph_count));

image

kphillisjr commented 6 years ago

I agree that there is definitely an Implementation bug with the texture atlas when you take into account additional languages. As far as the effected rendering systems I can confirm this will effect all 3D API's since by the specification the texture sizes can be different.

Note: In practice OpenGL Implementations can safely handle 2048 by 2048 pixels textures. The only case I know of where the limit is 1024px by 1024px is the Windows GDI driver for OpenGL which is limited to OpenGL Version 1.1.

Edit Fixed grammar and minor facts.

YukinoHayakawa commented 6 years ago

@kphillisjr Very useful summary of texture limits. I think this shows that the user definitely should have control over the texture size.

IvanFedotovIvanFedotov commented 5 years ago

Hello! We use your library to draw texts in a rectangles. The range of letters in the text is 2 languages ​​(Russian and English) and several letter sizes. For large letter sizes, the output texture begins to exceed the size of 512 * 32768 pixels. Both ranges with several letter sizes go in one atlas. Tell me please, is there any way or example how to solve this problem? Is another option also possible? Add functionality to your code so that the user can set the size of the atlas texture to the width. Different from 512 pixels?