Skip to content

Commit eb0e6ef

Browse files
authored
Added glyph ranges manager for ImGuiPresenter, added ability to use glyph ranges for Inspector's font (#1936)
* Added glyph manager for ImGuiPresenter * renamed glyph ranges constants * for static code conduct * for code of conduct 2 * removed some duplication and better format * removed extra space
1 parent ccf3189 commit eb0e6ef

File tree

6 files changed

+254
-31
lines changed

6 files changed

+254
-31
lines changed

extensions/ImGui/src/ImGui/ImGuiPresenter.cpp

Lines changed: 179 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
NS_AX_EXT_BEGIN
1818

19+
1920
namespace
2021
{
2122
uint32_t fourccValue(std::string_view str)
@@ -367,17 +368,13 @@ void ImGuiPresenter::loadCustomFonts(void* ud)
367368
auto contentZoomFactor = thiz->_contentZoomFactor;
368369
for (auto& fontInfo : thiz->_fontsInfoMap)
369370
{
370-
const ImWchar* imChars = nullptr;
371-
switch (fontInfo.second.glyphRange)
372-
{
373-
case CHS_GLYPH_RANGE::GENERAL:
374-
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
375-
break;
376-
case CHS_GLYPH_RANGE::FULL:
377-
imChars = imFonts->GetGlyphRangesChineseFull();
378-
break;
379-
default:;
380-
}
371+
auto& imChars = fontInfo.second.glyphRanges;
372+
// if the user has explicitly called `removeGlyphRanges` or replaced with new ranges
373+
if (imChars && !thiz->_usedGlyphRanges.contains((uintptr_t)imChars))
374+
imChars = nullptr;
375+
376+
if (imChars == nullptr && thiz->_glyphRanges.contains(fontInfo.second.glyphRangesId))
377+
imChars = thiz->_glyphRanges.at(fontInfo.second.glyphRangesId).data();
381378

382379
auto fontData = FileUtils::getInstance()->getDataFromFile(fontInfo.first);
383380
AXASSERT(!fontData.isNull(), "Cannot load font for IMGUI");
@@ -388,6 +385,8 @@ void ImGuiPresenter::loadCustomFonts(void* ud)
388385
imFonts->AddFontFromMemoryTTF(buffer, bufferSize, fontInfo.second.fontSize * contentZoomFactor, nullptr,
389386
imChars);
390387
}
388+
// the temporary bucket gets emptied out
389+
thiz->_eraseGlyphRanges.clear();
391390
}
392391

393392
float ImGuiPresenter::enableDPIScale(float userScale)
@@ -424,11 +423,54 @@ void ImGuiPresenter::setViewResolution(float width, float height)
424423
ImGui_ImplAx_SetViewResolution(width, height);
425424
}
426425

427-
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, CHS_GLYPH_RANGE glyphRange)
426+
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, GLYPH_RANGES glyphRange)
427+
{
428+
addGlyphRanges(glyphRange);
429+
std::string_view glyphId = getGlyphRangesId(glyphRange);
430+
addFont(fontFile, fontSize, glyphId);
431+
}
432+
433+
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, std::string_view glyphRangeId)
434+
{
435+
auto it = _glyphRanges.find(glyphRangeId);
436+
if (it == _glyphRanges.end())
437+
{
438+
addFont(fontFile, fontSize, std::vector<ImWchar>(0));
439+
return;
440+
}
441+
442+
if (FileUtils::getInstance()->isFileExistInternal(fontFile))
443+
{
444+
ImWchar* imChars = it->second.data();
445+
446+
bool isDirty = _fontsInfoMap.emplace(fontFile, FontInfo{fontSize, imChars, std::string(glyphRangeId)}).second;
447+
isDirty |=
448+
_usedGlyphRanges.emplace((uintptr_t)imChars).second || _fontsInfoMap.at(fontFile).glyphRanges != imChars;
449+
if (isDirty)
450+
ImGui_ImplAx_SetDeviceObjectsDirty();
451+
}
452+
}
453+
454+
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, const std::vector<ImWchar>& glyphRanges)
455+
{
456+
addFont(fontFile, fontSize, fontFile, glyphRanges);
457+
}
458+
459+
void ImGuiPresenter::addFont(std::string_view fontFile,
460+
float fontSize,
461+
std::string_view glyphRangesId,
462+
const std::vector<ImWchar>& glyphRanges)
428463
{
429464
if (FileUtils::getInstance()->isFileExistInternal(fontFile))
430465
{
431-
if (_fontsInfoMap.emplace(fontFile, FontInfo{fontSize, glyphRange}).second)
466+
ImWchar* imChars = nullptr;
467+
if (!glyphRanges.empty())
468+
imChars = addGlyphRanges(glyphRangesId, glyphRanges);
469+
470+
bool isDirty = _fontsInfoMap.emplace(fontFile, FontInfo{fontSize, imChars, std::string(glyphRangesId)}).second;
471+
isDirty |= imChars && (_usedGlyphRanges.emplace((uintptr_t)imChars).second ||
472+
_fontsInfoMap.at(fontFile).glyphRanges != imChars);
473+
if (isDirty)
432474
ImGui_ImplAx_SetDeviceObjectsDirty();
433475
}
434476
}
@@ -853,18 +895,110 @@ void ImGuiPresenter::setLabelColor(Label* label, ImGuiCol col)
853895
setLabelColor(label, ImGui::GetStyleColorVec4(col));
854896
}
855897

898+
ImWchar* ImGuiPresenter::addGlyphRanges(GLYPH_RANGES glyphRange)
899+
{
900+
static std::unordered_map<GLYPH_RANGES, size_t> _glyph_ranges_size;
901+
auto imFonts = ImGui::GetIO().Fonts;
902+
const ImWchar* imChars;
903+
904+
switch (glyphRange)
905+
{
906+
case GLYPH_RANGES::DEFAULT:
907+
imChars = imFonts->GetGlyphRangesDefault();
908+
break;
909+
case GLYPH_RANGES::GREEK:
910+
imChars = imFonts->GetGlyphRangesGreek();
911+
break;
912+
case GLYPH_RANGES::KOREAN:
913+
imChars = imFonts->GetGlyphRangesKorean();
914+
break;
915+
case GLYPH_RANGES::CHINESE_GENERAL:
916+
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
917+
break;
918+
case GLYPH_RANGES::CHINESE_FULL:
919+
imChars = imFonts->GetGlyphRangesChineseFull();
920+
break;
921+
case GLYPH_RANGES::JAPANESE:
922+
imChars = imFonts->GetGlyphRangesJapanese();
923+
break;
924+
case GLYPH_RANGES::CYRILLIC:
925+
imChars = imFonts->GetGlyphRangesCyrillic();
926+
break;
927+
case GLYPH_RANGES::THAI:
928+
imChars = imFonts->GetGlyphRangesThai();
929+
break;
930+
case GLYPH_RANGES::VIETNAMESE:
931+
imChars = imFonts->GetGlyphRangesVietnamese();
932+
break;
933+
default:
934+
return nullptr;
935+
}
936+
937+
size_t imCharsSize = 0;
938+
if (_glyph_ranges_size.contains(glyphRange))
939+
imCharsSize = _glyph_ranges_size[glyphRange];
940+
else
941+
{
942+
// must always end with 0
943+
while (imChars[imCharsSize] != 0)
944+
imCharsSize++;
945+
imCharsSize += 1;
946+
_glyph_ranges_size[glyphRange] = imCharsSize;
947+
}
948+
auto glyphId = getGlyphRangesId(glyphRange);
949+
950+
return addGlyphRanges(glyphId, std::vector<ImWchar>(imChars, imChars + imCharsSize));
951+
}
952+
856953
ImWchar* ImGuiPresenter::addGlyphRanges(std::string_view key, const std::vector<ImWchar>& ranges)
857954
{
858-
auto it = glyphRanges.find(key);
859-
// the pointer must be persistant, do not replace
860-
if (it != glyphRanges.end())
861-
return it->second.data();
862-
it = glyphRanges.emplace(key, ranges).first; // glyphRanges[key] = ranges;
955+
auto it = _glyphRanges.find(key);
956+
// store in our temporary bucket if already exists...
957+
if (it != _glyphRanges.end())
958+
{
959+
// so that `loadCustomFonts` can look for the new "replaced" glyph ranges
960+
_usedGlyphRanges.erase((uintptr_t)it->second.data());
961+
// probably automatically gets *moved* but to make our intention more clear
962+
_eraseGlyphRanges.push_back(std::move(it->second));
963+
}
964+
it = _glyphRanges.emplace(key, ranges).first; // _glyphRanges[key] = ranges;
863965
if (ranges.empty())
864966
it->second.push_back(0);
967+
// the `addFont` will call `ImGui_ImplAx_SetDeviceObjectsDirty` if everything is okay,
968+
// no need to call it if no font is using the glyph ranges...
865969
return it->second.data();
866970
}
867971

972+
void ImGuiPresenter::removeGlyphRanges(std::string_view key)
973+
{
974+
auto removeGlyphRange = _glyphRanges.find(key);
975+
if (removeGlyphRange == _glyphRanges.end())
976+
return;
977+
978+
auto usedCount = _usedGlyphRanges.size();
979+
_usedGlyphRanges.erase((uintptr_t)removeGlyphRange->second.data());
980+
_eraseGlyphRanges.push_back(std::move(removeGlyphRange->second));
981+
_glyphRanges.erase(key);
982+
983+
// update the fonts to not use the glyph ranges since user wants to remove it for some reason..
984+
if (_usedGlyphRanges.size() != usedCount)
985+
ImGui_ImplAx_SetDeviceObjectsDirty();
986+
}
987+
988+
void ImGuiPresenter::clearGlyphRanges()
989+
{
990+
auto usedCount = _usedGlyphRanges.size();
991+
for (auto& glyphRange : _glyphRanges)
992+
{
993+
_usedGlyphRanges.erase((uintptr_t)glyphRange.second.data());
994+
_eraseGlyphRanges.push_back(std::move(glyphRange.second));
995+
}
996+
_glyphRanges.clear();
997+
998+
if (_usedGlyphRanges.size() != usedCount)
999+
ImGui_ImplAx_SetDeviceObjectsDirty();
1000+
}
1001+
8681002
void ImGuiPresenter::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end)
8691003
{
8701004
if (!dst || !src || start > end)
@@ -901,4 +1035,31 @@ int ImGuiPresenter::getCCRefId(Object* p)
9011035
return (int)hash;
9021036
}
9031037

1038+
std::string_view ImGuiPresenter::getGlyphRangesId(GLYPH_RANGES glyphRanges)
1039+
{
1040+
switch (glyphRanges)
1041+
{
1042+
case GLYPH_RANGES::DEFAULT:
1043+
return GLYPH_RANGES_DEFAULT_ID;
1044+
case GLYPH_RANGES::GREEK:
1045+
return GLYPH_RANGES_GREEK_ID;
1046+
case GLYPH_RANGES::KOREAN:
1047+
return GLYPH_RANGES_KOREAN_ID;
1048+
case GLYPH_RANGES::CHINESE_GENERAL:
1049+
return GLYPH_RANGES_CHINESE_GENERAL_ID;
1050+
case GLYPH_RANGES::CHINESE_FULL:
1051+
return GLYPH_RANGES_CHINESE_FULL_ID;
1052+
case GLYPH_RANGES::JAPANESE:
1053+
return GLYPH_RANGES_JAPANESE_ID;
1054+
case GLYPH_RANGES::CYRILLIC:
1055+
return GLYPH_RANGES_CYRILLIC_ID;
1056+
case GLYPH_RANGES::THAI:
1057+
return GLYPH_RANGES_THAI_ID;
1058+
case GLYPH_RANGES::VIETNAMESE:
1059+
return GLYPH_RANGES_VIETNAMESE_ID;
1060+
default:
1061+
return "";
1062+
}
1063+
}
1064+
9041065
NS_AX_EXT_END

extensions/ImGui/src/ImGui/ImGuiPresenter.h

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,33 @@ class ImGuiPresenter
2020
void cleanup();
2121

2222
public:
23-
enum class CHS_GLYPH_RANGE
23+
inline static const std::string_view GLYPH_RANGES_DEFAULT_ID = "__DEFAULT_GLYPH__";
24+
inline static const std::string_view GLYPH_RANGES_GREEK_ID = "__GREEK_GLYPH__";
25+
inline static const std::string_view GLYPH_RANGES_KOREAN_ID = "__KOREAN_GLYPH__";
26+
inline static const std::string_view GLYPH_RANGES_CHINESE_GENERAL_ID = "__CHINESE_SIMPLIFIED_COMMON_GLYPH__";
27+
inline static const std::string_view GLYPH_RANGES_CHINESE_FULL_ID = "__CHINESE_FULL_GLYPH__";
28+
inline static const std::string_view GLYPH_RANGES_JAPANESE_ID = "__JAPANESE_GLYPH__";
29+
inline static const std::string_view GLYPH_RANGES_CYRILLIC_ID = "__CYRILLIC_GLYPH__";
30+
inline static const std::string_view GLYPH_RANGES_THAI_ID = "__THAI_GLYPH__";
31+
inline static const std::string_view GLYPH_RANGES_VIETNAMESE_ID = "__VIETNAMESE_GLYPH__";
32+
33+
// predefined glyph ranges by imgui
34+
enum class GLYPH_RANGES
2435
{
2536
NONE,
26-
GENERAL,
27-
FULL
37+
DEFAULT,
38+
GREEK,
39+
KOREAN,
40+
CHINESE_GENERAL,
41+
CHINESE_FULL,
42+
JAPANESE,
43+
CYRILLIC,
44+
THAI,
45+
VIETNAMESE
2846
};
2947

48+
static std::string_view getGlyphRangesId(GLYPH_RANGES glyphRanges);
49+
3050
enum
3151
{
3252
DEFAULT_FONT_SIZE = 13 // see imgui.cpp
@@ -57,8 +77,30 @@ class ImGuiPresenter
5777
/// <param name="fontFile"></param>
5878
/// <param name="glyphRange"></param>
5979
void addFont(std::string_view fontFile,
60-
float fontSize = DEFAULT_FONT_SIZE,
61-
CHS_GLYPH_RANGE glyphRange = CHS_GLYPH_RANGE::NONE);
80+
float fontSize = DEFAULT_FONT_SIZE,
81+
GLYPH_RANGES glyphRange = GLYPH_RANGES::NONE);
82+
/// <summary>
83+
/// Add ImGui font with contentZoomFactor and use pre-existing glyph range for the specified font
84+
/// </summary>
85+
/// <param name="fontFile"></param>
86+
/// <param name="glyphRanges">The glyph range vector must end with 0 and it should be included in the size</param>
87+
void addFont(std::string_view fontFile, float fontSize, std::string_view glyphRangesId);
88+
/// <summary>
89+
/// Add ImGui font with contentZoomFactor and use specified custom glyph range for the specified font
90+
/// </summary>
91+
/// <param name="fontFile"></param>
92+
/// <param name="glyphRange">The glyph range vector must end with 0 and it should be included in the size</param>
93+
void addFont(std::string_view fontFile, float fontSize, const std::vector<ImWchar>& glyphRanges);
94+
/// <summary>
95+
/// Add ImGui font with contentZoomFactor and use custom glyph range and specify a custom id
96+
/// </summary>
97+
/// <param name="fontFile"></param>
98+
/// <param name="glyphRangesId">Custom Lookup Id</param>
99+
/// <param name="glyphRanges">The glyph range vector must end with 0 and it should be included in the size</param>
100+
void addFont(std::string_view fontFile,
101+
float fontSize,
102+
std::string_view glyphRangesId,
103+
const std::vector<ImWchar>& glyphRanges);
62104
void removeFont(std::string_view fontFile);
63105
void clearFonts();
64106

@@ -124,7 +166,10 @@ class ImGuiPresenter
124166
static void setLabelColor(Label* label, bool disabled = false);
125167
static void setLabelColor(Label* label, ImGuiCol col);
126168

169+
ImWchar* addGlyphRanges(GLYPH_RANGES glyphRange);
127170
ImWchar* addGlyphRanges(std::string_view key, const std::vector<ImWchar>& ranges);
171+
void removeGlyphRanges(std::string_view key);
172+
void clearGlyphRanges();
128173
static void mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end);
129174
int getCCRefId(Object* p);
130175

@@ -151,7 +196,11 @@ class ImGuiPresenter
151196
std::unordered_map<Object*, int> usedCCRefIdMap;
152197
// cocos objects should be retained until next frame
153198
Vector<Object*> usedCCRef;
154-
hlookup::string_map<std::vector<ImWchar>> glyphRanges;
199+
200+
hlookup::string_map<std::vector<ImWchar>> _glyphRanges;
201+
std::unordered_set<uintptr_t> _usedGlyphRanges; // there should be one intance of "each glyph ranges"
202+
// temporarily stores the current erased/replaced ranges, gets cleared in the next `loadCustomFonts` interation
203+
std::vector<std::vector<ImWchar>> _eraseGlyphRanges;
155204

156205
float _contentZoomFactor = 1.0f;
157206

@@ -162,7 +211,8 @@ class ImGuiPresenter
162211
struct FontInfo
163212
{
164213
float fontSize;
165-
CHS_GLYPH_RANGE glyphRange;
214+
ImWchar* glyphRanges;
215+
std::string glyphRangesId;
166216
};
167217

168218
hlookup::string_map<FontInfo> _fontsInfoMap;

extensions/ImGui/src/ImGui/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Sync from https://github.com/Xrysnow/cocos2d-x-imgui and do a little changes
99
* Use ```FOURCC``` for key of ImGui render loop
1010
* Add dpi scale support, use ```ImGuiPresenter::getInstance()->enableDPIScale();```
1111
* Easy font manager, stable API ```addFont,removeFont,clearFonts``` to manage ImGui fonts, with ImGui API, very hard to do correctly.
12+
* Easy to add/use custom or imgui pre-defined glyph ranges ```ImGuiPresenter::GLYPH_RANGES,addGlyphRanges,removeGlyphRanges```
13+
and then specify the glyph ranges id while calling `addFont`
14+
to use those with specific font.
1215

1316
## How to use
1417
```cpp
@@ -24,7 +27,7 @@ public:
2427
ImGuiPresenter::getInstance()->addFont(R"(C:\Windows\Fonts\msyh.ttc)");
2528
/* For Simplified Chinese support, please use:
2629
ImGuiPresenter::getInstance()->addFont(R"(C:\Windows\Fonts\msyh.ttc)", ImGuiPresenter::DEFAULT_FONT_SIZE,
27-
ImGuiPresenter::CHS_GLYPH_RANGE::GENERAL);
30+
ImGuiPresenter::GLYPH_RANGES::CHINESE_GENERAL);
2831
*/
2932
ImGuiPresenter::getInstance()->enableDPIScale(); // enable dpi scale for 4K display support, depends at least one valid ttf/ttc font was added.
3033
ImGuiPresenter::getInstance()->addRenderLoop("#im01", AX_CALLBACK_0(GameScene::onImGuiDraw, this), this);

extensions/Inspector/src/Inspector/Inspector.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,15 @@ void Inspector::setFontSize(float fontSize)
177177
_fontSize = fontSize;
178178
}
179179

180+
void Inspector::setFontGlyphId(std::string_view glyphId)
181+
{
182+
_fontGlyphId = std::string(glyphId);
183+
}
184+
180185
void Inspector::init()
181186
{
182187
_fontPath = "fonts/arial.ttf";
188+
_fontSize = ImGuiPresenter::DEFAULT_FONT_SIZE;
183189

184190
addPropertyHandler("__NODE__", std::make_unique<InspectorNodePropertyHandler>());
185191
addPropertyHandler("__SPRITE__", std::make_unique<InspectorSpritePropertyHandler>());
@@ -399,7 +405,7 @@ void Inspector::openForScene(Scene* target)
399405
}
400406

401407
auto* presenter = ImGuiPresenter::getInstance();
402-
presenter->addFont(FileUtils::getInstance()->fullPathForFilename(_fontPath), _fontSize);
408+
presenter->addFont(FileUtils::getInstance()->fullPathForFilename(_fontPath), _fontSize, _fontGlyphId);
403409
presenter->enableDPIScale();
404410
presenter->addRenderLoop("#insp", AX_CALLBACK_0(Inspector::mainLoop , this), target);
405411
}

0 commit comments

Comments
 (0)