Font Atlas Texturesize too big ? #491

Closed
opened 2016-01-19 17:42:53 +00:00 by MINIONBOTS · 9 comments
MINIONBOTS commented 2016-01-19 17:42:53 +00:00 (Migrated from github.com)

Hi,
I added 4 seperate .ttf files to cover all the kinky utf8 characters. It all works nicely, but people running integrated graphics are crashing nicely.

http://pasteboard.co/UMqJv3C.png

If I take out 2 of the files, the texture gets smaller and everything is good. Could that be the reason, that the texture is too large and the little "gpus" cannot deal with it? Do you have any idea how I can work around this ? I'm using the DX9 code.

I tried making 4 x "DefaultLanguage" + add each time one of the .ttf files, so that I would always have the GetGlyphRangesDefault merged with one of the specific languages (Korean / Chines / Russian / Japanese). Sadly I fail to get this to work. Maybe you have a tiny hint how I have to approach this codewise ?

currently I was doing this:

io.Fonts->AddFontDefault();     
...
ImFontConfig config;
config.MergeMode = true;
io.Fonts->AddFontFromFileTTF(...TTF1...), 16.0f, &config, io.Fonts->GetGlyphRangesCyrillic());

ImFontConfig config2;
config2.MergeMode = true;
io.Fonts->AddFontFromFileTTF(...TTF2...), 14.0f,&config3,io.Fonts->GetGlyphRangesKorean());
.... and so on....
Hi, I added 4 seperate .ttf files to cover all the kinky utf8 characters. It all works nicely, but people running integrated graphics are crashing nicely. http://pasteboard.co/UMqJv3C.png If I take out 2 of the files, the texture gets smaller and everything is good. Could that be the reason, that the texture is too large and the little "gpus" cannot deal with it? Do you have any idea how I can work around this ? I'm using the DX9 code. I tried making 4 x "DefaultLanguage" + add each time one of the .ttf files, so that I would always have the GetGlyphRangesDefault merged with one of the specific languages (Korean / Chines / Russian / Japanese). Sadly I fail to get this to work. Maybe you have a tiny hint how I have to approach this codewise ? currently I was doing this: ``` io.Fonts->AddFontDefault(); ... ImFontConfig config; config.MergeMode = true; io.Fonts->AddFontFromFileTTF(...TTF1...), 16.0f, &config, io.Fonts->GetGlyphRangesCyrillic()); ImFontConfig config2; config2.MergeMode = true; io.Fonts->AddFontFromFileTTF(...TTF2...), 14.0f,&config3,io.Fonts->GetGlyphRangesKorean()); .... and so on.... ```
MINIONBOTS commented 2016-01-19 19:02:02 +00:00 (Migrated from github.com)

As usual, after asking for help, I found a way to create 4 fonts with default + ttf loaded.
Is it supposed to be done like this ?
'''
io.Fonts->AddFontDefault();
ImFontConfig config;
strcpy(config.Name, "Cyrillic");
config.MergeMode = true;
io.Fonts->AddFontFromFileTTF(..TTF1..), 16.0f, &config, io.Fonts->GetGlyphRangesCyrillic());

ImFontConfig config2;
config2.OversampleH = 1;
config2.OversampleV = 1;
config2.PixelSnapH = true;
config2.MergeMode = false;
strcpy(config2.Name, "");
io.Fonts->AddFontDefault(&config2);
strcpy(config2.Name, "Chinese");
config2.MergeMode = true;
io.Fonts->AddFontFromFileTTF(..TTF2...), 14.0f,&config2,io.Fonts->GetGlyphRangesChinese());
'''
...
My initial question regarding the very large texture + crash still stands, :)

As usual, after asking for help, I found a way to create 4 fonts with default + ttf loaded. Is it supposed to be done like this ? ''' io.Fonts->AddFontDefault(); ImFontConfig config; strcpy(config.Name, "Cyrillic"); config.MergeMode = true; io.Fonts->AddFontFromFileTTF(..TTF1..), 16.0f, &config, io.Fonts->GetGlyphRangesCyrillic()); ImFontConfig config2; config2.OversampleH = 1; config2.OversampleV = 1; config2.PixelSnapH = true; config2.MergeMode = false; strcpy(config2.Name, "<default>"); io.Fonts->AddFontDefault(&config2); strcpy(config2.Name, "Chinese"); config2.MergeMode = true; io.Fonts->AddFontFromFileTTF(..TTF2...), 14.0f,&config2,io.Fonts->GetGlyphRangesChinese()); ''' ... My initial question regarding the very large texture + crash still stands, :)
MrSapps commented 2016-01-19 20:10:46 +00:00 (Migrated from github.com)

I think this has been asked before, its because every glyph from the ttf is added, and there are a LOT in there. Some way of picking the used glyphs or something is probably the only way to solve it while still using the same ttf file I think.

I think this has been asked before, its because every glyph from the ttf is added, and there are a LOT in there. Some way of picking the used glyphs or something is probably the only way to solve it while still using the same ttf file I think.
MINIONBOTS commented 2016-01-20 09:53:46 +00:00 (Migrated from github.com)

well, I guess I'll go with an not so nice language selector then, thanks for the reply !
I love that project :)

well, I guess I'll go with an not so nice language selector then, thanks for the reply ! I love that project :)
ocornut commented 2016-01-20 10:10:46 +00:00 (Migrated from github.com)

There's a few things involved.

A) First, integrated graphics drivers have limit on texture size on each axis. ImGui default to a 2048 pixel wide texture here. You can do Fonts.TexDesiredWidth = 8096; to manually set the texture width and then the height will be reduced and it may just work.

Perhaps we should tweak this section of the code in imgui_draw.cpp to further increase the default width is not specified:

TexWidth = (TexDesiredWidth > 0) ? TexDesiredWidth : (total_glyph_count > 2000) ? 2048 : (total_glyph_count > 1000) ? 1024 : 512; // Width doesn't actually matters much but some API/GPU have texture size limitations, and increasing width can decrease height.

B) As you pointed out, reducing the amount of Oversampling will also get you smaller textures.

C) If you are running a game with known script the best solution is probably to compute your glyph ranges based on what you script actually uses, because most of those Chinese characters will be very unlikely used.

D) ImGui needs a way ot dynamically filling the font atlas, it's been in my todo list for a while but isn't a top priority. It's not an hard task but it needs to be done in a very careful and precise manner to not hurt performances as text size calculation is a known bottleneck.

There's a few things involved. A) First, integrated graphics drivers have limit on texture size on each axis. ImGui default to a 2048 pixel wide texture here. You can do `Fonts.TexDesiredWidth = 8096;` to manually set the texture width and then the height will be reduced and it may just work. Perhaps we should tweak this section of the code in imgui_draw.cpp to further increase the default width is not specified: `TexWidth = (TexDesiredWidth > 0) ? TexDesiredWidth : (total_glyph_count > 2000) ? 2048 : (total_glyph_count > 1000) ? 1024 : 512; // Width doesn't actually matters much but some API/GPU have texture size limitations, and increasing width can decrease height.` B) As you pointed out, reducing the amount of Oversampling will also get you smaller textures. C) If you are running a game with known script the best solution is probably to compute your glyph ranges based on what you script actually uses, because most of those Chinese characters will be very unlikely used. D) ImGui needs a way ot dynamically filling the font atlas, it's been in my todo list for a while but isn't a top priority. It's not an hard task but it needs to be done in a very careful and precise manner to not hurt performances as text size calculation is a known bottleneck.
MINIONBOTS commented 2016-01-21 12:41:19 +00:00 (Migrated from github.com)

Thanks for the response!
:)

Thanks for the response! :)
xingyun86 commented 2021-12-23 07:44:28 +00:00 (Migrated from github.com)

Big chinese font problem solved.

Big chinese font problem solved.
Hoek67 commented 2022-06-14 15:53:34 +00:00 (Migrated from github.com)

Hi just wondering if there is a limit on the number of fonts per atlas?

Trying to get a drop down list or similar of all the fonts in the system font directory and when each is clicked a small sample bit of text is displayed.

It seems to "work" except fa.GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_pp); returns no data.

If I try with "ar*.ttf" it works fine and the texture is quite small.

Other thing I was thinking was one of the loaded TTF's is the cause and not necessarily the number of fonts.

My test code is below....
[code]

void getfonts()
{
	ImFontAtlas fa; // only need a temp one...  for testing

	int width, height;
	int bytes_pp;

	ImVector<ImWchar> ranges;

	ImFontConfig config;
	config.OversampleH = 2;
	config.OversampleV = 1;
	config.GlyphExtraSpacing.x = 1.0f;
			

	ImFontGlyphRangesBuilder builder;

	builder.AddText("1234"); // always added
	builder.BuildRanges(&ranges);

	WIN32_FIND_DATAA FindData;
	HANDLE hnd = FindFirstFileA("e:\\windows\\fonts\\a*.ttf", &FindData);
	int cnt = 0;

	if (hnd)
	{
		for (;;)
		{
			char full[500];

			strcpy(full, "e:\\windows\\fonts\\");
			strcat(full, FindData.cFileName);

			ImFont* fnt = fa.AddFontFromFileTTF(full, 16.0f, NULL, ranges.Data);

			cnt++;

			if (!FindNextFileA(hnd, &FindData))
			{
				break;
			}
		}

		FindClose(hnd);

	}
	
	BYTE* pixels;

	fa.GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_pp);

	if (pixels)
	{
		gobTexture* tex = new gobTexture();
		tex->LoadCopyData(width, height, (DWORD*)pixels);
		tex->CopyTextureToShader(0);
		TextureManager.AddTexture(tex, "FONT_ENUM", 0);
	}
}

[/code]

Hi just wondering if there is a limit on the number of fonts per atlas? Trying to get a drop down list or similar of all the fonts in the system font directory and when each is clicked a small sample bit of text is displayed. It seems to "work" except fa.GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_pp); returns no data. If I try with "ar*.ttf" it works fine and the texture is quite small. Other thing I was thinking was one of the loaded TTF's is the cause and not necessarily the number of fonts. My test code is below.... [code] void getfonts() { ImFontAtlas fa; // only need a temp one... for testing int width, height; int bytes_pp; ImVector<ImWchar> ranges; ImFontConfig config; config.OversampleH = 2; config.OversampleV = 1; config.GlyphExtraSpacing.x = 1.0f; ImFontGlyphRangesBuilder builder; builder.AddText("1234"); // always added builder.BuildRanges(&ranges); WIN32_FIND_DATAA FindData; HANDLE hnd = FindFirstFileA("e:\\windows\\fonts\\a*.ttf", &FindData); int cnt = 0; if (hnd) { for (;;) { char full[500]; strcpy(full, "e:\\windows\\fonts\\"); strcat(full, FindData.cFileName); ImFont* fnt = fa.AddFontFromFileTTF(full, 16.0f, NULL, ranges.Data); cnt++; if (!FindNextFileA(hnd, &FindData)) { break; } } FindClose(hnd); } BYTE* pixels; fa.GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_pp); if (pixels) { gobTexture* tex = new gobTexture(); tex->LoadCopyData(width, height, (DWORD*)pixels); tex->CopyTextureToShader(0); TextureManager.AddTexture(tex, "FONT_ENUM", 0); } } [/code]
Hoek67 commented 2022-06-14 17:02:55 +00:00 (Migrated from github.com)

Update : Not too sure if it's a bug or not....

It seems if you load a font with a range ... say the text "12345" (like above) and the font is loaded but that range is not in the actual font the pixel build fails. I took out the range bit and it seems quite happy chugging out 20 full fonts into the bitmap. (see screen capture). However it got upset with a small build where a font was missing the range of desired characters.

The question is I guess... should this stop the font being built as usually fallback characters are utilized.... or do I have to make sure it includes these fallback characters in the range?
image

Other than that though... getting more and more impressed by ImGui. Got custom icons working well and even have so when used in a radio button group the unselected ones are grayscale.

Update : Not too sure if it's a bug or not.... It seems if you load a font with a range ... say the text "12345" (like above) and the font is loaded but that range is not in the actual font the pixel build fails. I took out the range bit and it seems quite happy chugging out 20 full fonts into the bitmap. (see screen capture). However it got upset with a small build where a font was missing the range of desired characters. The question is I guess... should this stop the font being built as usually fallback characters are utilized.... or do I have to make sure it includes these fallback characters in the range? ![image](https://user-images.githubusercontent.com/18671600/173633917-ff4042ed-d3cc-4bd3-9bea-817213e75234.png) Other than that though... getting more and more impressed by ImGui. Got custom icons working well and even have so when used in a radio button group the unselected ones are grayscale.
Hoek67 commented 2022-06-14 19:10:59 +00:00 (Migrated from github.com)

For solution (that fixed it for me) see https://github.com/nothings/stb/issues/1086

For solution (that fixed it for me) see https://github.com/nothings/stb/issues/1086
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ocornut/imgui#491
No description provided.