mirror of https://github.com/axmolengine/axmol.git
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
This commit is contained in:
parent
ccf31892a0
commit
eb0e6ef50d
|
@ -16,6 +16,7 @@
|
|||
|
||||
NS_AX_EXT_BEGIN
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
uint32_t fourccValue(std::string_view str)
|
||||
|
@ -367,17 +368,13 @@ void ImGuiPresenter::loadCustomFonts(void* ud)
|
|||
auto contentZoomFactor = thiz->_contentZoomFactor;
|
||||
for (auto& fontInfo : thiz->_fontsInfoMap)
|
||||
{
|
||||
const ImWchar* imChars = nullptr;
|
||||
switch (fontInfo.second.glyphRange)
|
||||
{
|
||||
case CHS_GLYPH_RANGE::GENERAL:
|
||||
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
|
||||
break;
|
||||
case CHS_GLYPH_RANGE::FULL:
|
||||
imChars = imFonts->GetGlyphRangesChineseFull();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
auto& imChars = fontInfo.second.glyphRanges;
|
||||
// if the user has explicitly called `removeGlyphRanges` or replaced with new ranges
|
||||
if (imChars && !thiz->_usedGlyphRanges.contains((uintptr_t)imChars))
|
||||
imChars = nullptr;
|
||||
|
||||
if (imChars == nullptr && thiz->_glyphRanges.contains(fontInfo.second.glyphRangesId))
|
||||
imChars = thiz->_glyphRanges.at(fontInfo.second.glyphRangesId).data();
|
||||
|
||||
auto fontData = FileUtils::getInstance()->getDataFromFile(fontInfo.first);
|
||||
AXASSERT(!fontData.isNull(), "Cannot load font for IMGUI");
|
||||
|
@ -388,6 +385,8 @@ void ImGuiPresenter::loadCustomFonts(void* ud)
|
|||
imFonts->AddFontFromMemoryTTF(buffer, bufferSize, fontInfo.second.fontSize * contentZoomFactor, nullptr,
|
||||
imChars);
|
||||
}
|
||||
// the temporary bucket gets emptied out
|
||||
thiz->_eraseGlyphRanges.clear();
|
||||
}
|
||||
|
||||
float ImGuiPresenter::enableDPIScale(float userScale)
|
||||
|
@ -424,11 +423,54 @@ void ImGuiPresenter::setViewResolution(float width, float height)
|
|||
ImGui_ImplAx_SetViewResolution(width, height);
|
||||
}
|
||||
|
||||
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, CHS_GLYPH_RANGE glyphRange)
|
||||
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, GLYPH_RANGES glyphRange)
|
||||
{
|
||||
addGlyphRanges(glyphRange);
|
||||
std::string_view glyphId = getGlyphRangesId(glyphRange);
|
||||
addFont(fontFile, fontSize, glyphId);
|
||||
}
|
||||
|
||||
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, std::string_view glyphRangeId)
|
||||
{
|
||||
auto it = _glyphRanges.find(glyphRangeId);
|
||||
if (it == _glyphRanges.end())
|
||||
{
|
||||
addFont(fontFile, fontSize, std::vector<ImWchar>(0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (FileUtils::getInstance()->isFileExistInternal(fontFile))
|
||||
{
|
||||
ImWchar* imChars = it->second.data();
|
||||
|
||||
bool isDirty = _fontsInfoMap.emplace(fontFile, FontInfo{fontSize, imChars, std::string(glyphRangeId)}).second;
|
||||
isDirty |=
|
||||
_usedGlyphRanges.emplace((uintptr_t)imChars).second || _fontsInfoMap.at(fontFile).glyphRanges != imChars;
|
||||
if (isDirty)
|
||||
ImGui_ImplAx_SetDeviceObjectsDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiPresenter::addFont(std::string_view fontFile, float fontSize, const std::vector<ImWchar>& glyphRanges)
|
||||
{
|
||||
addFont(fontFile, fontSize, fontFile, glyphRanges);
|
||||
}
|
||||
|
||||
void ImGuiPresenter::addFont(std::string_view fontFile,
|
||||
float fontSize,
|
||||
std::string_view glyphRangesId,
|
||||
const std::vector<ImWchar>& glyphRanges)
|
||||
{
|
||||
if (FileUtils::getInstance()->isFileExistInternal(fontFile))
|
||||
{
|
||||
if (_fontsInfoMap.emplace(fontFile, FontInfo{fontSize, glyphRange}).second)
|
||||
ImWchar* imChars = nullptr;
|
||||
if (!glyphRanges.empty())
|
||||
imChars = addGlyphRanges(glyphRangesId, glyphRanges);
|
||||
|
||||
bool isDirty = _fontsInfoMap.emplace(fontFile, FontInfo{fontSize, imChars, std::string(glyphRangesId)}).second;
|
||||
isDirty |= imChars && (_usedGlyphRanges.emplace((uintptr_t)imChars).second ||
|
||||
_fontsInfoMap.at(fontFile).glyphRanges != imChars);
|
||||
if (isDirty)
|
||||
ImGui_ImplAx_SetDeviceObjectsDirty();
|
||||
}
|
||||
}
|
||||
|
@ -853,18 +895,110 @@ void ImGuiPresenter::setLabelColor(Label* label, ImGuiCol col)
|
|||
setLabelColor(label, ImGui::GetStyleColorVec4(col));
|
||||
}
|
||||
|
||||
ImWchar* ImGuiPresenter::addGlyphRanges(GLYPH_RANGES glyphRange)
|
||||
{
|
||||
static std::unordered_map<GLYPH_RANGES, size_t> _glyph_ranges_size;
|
||||
auto imFonts = ImGui::GetIO().Fonts;
|
||||
const ImWchar* imChars;
|
||||
|
||||
switch (glyphRange)
|
||||
{
|
||||
case GLYPH_RANGES::DEFAULT:
|
||||
imChars = imFonts->GetGlyphRangesDefault();
|
||||
break;
|
||||
case GLYPH_RANGES::GREEK:
|
||||
imChars = imFonts->GetGlyphRangesGreek();
|
||||
break;
|
||||
case GLYPH_RANGES::KOREAN:
|
||||
imChars = imFonts->GetGlyphRangesKorean();
|
||||
break;
|
||||
case GLYPH_RANGES::CHINESE_GENERAL:
|
||||
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
|
||||
break;
|
||||
case GLYPH_RANGES::CHINESE_FULL:
|
||||
imChars = imFonts->GetGlyphRangesChineseFull();
|
||||
break;
|
||||
case GLYPH_RANGES::JAPANESE:
|
||||
imChars = imFonts->GetGlyphRangesJapanese();
|
||||
break;
|
||||
case GLYPH_RANGES::CYRILLIC:
|
||||
imChars = imFonts->GetGlyphRangesCyrillic();
|
||||
break;
|
||||
case GLYPH_RANGES::THAI:
|
||||
imChars = imFonts->GetGlyphRangesThai();
|
||||
break;
|
||||
case GLYPH_RANGES::VIETNAMESE:
|
||||
imChars = imFonts->GetGlyphRangesVietnamese();
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t imCharsSize = 0;
|
||||
if (_glyph_ranges_size.contains(glyphRange))
|
||||
imCharsSize = _glyph_ranges_size[glyphRange];
|
||||
else
|
||||
{
|
||||
// must always end with 0
|
||||
while (imChars[imCharsSize] != 0)
|
||||
imCharsSize++;
|
||||
imCharsSize += 1;
|
||||
_glyph_ranges_size[glyphRange] = imCharsSize;
|
||||
}
|
||||
auto glyphId = getGlyphRangesId(glyphRange);
|
||||
|
||||
return addGlyphRanges(glyphId, std::vector<ImWchar>(imChars, imChars + imCharsSize));
|
||||
}
|
||||
|
||||
ImWchar* ImGuiPresenter::addGlyphRanges(std::string_view key, const std::vector<ImWchar>& ranges)
|
||||
{
|
||||
auto it = glyphRanges.find(key);
|
||||
// the pointer must be persistant, do not replace
|
||||
if (it != glyphRanges.end())
|
||||
return it->second.data();
|
||||
it = glyphRanges.emplace(key, ranges).first; // glyphRanges[key] = ranges;
|
||||
auto it = _glyphRanges.find(key);
|
||||
// store in our temporary bucket if already exists...
|
||||
if (it != _glyphRanges.end())
|
||||
{
|
||||
// so that `loadCustomFonts` can look for the new "replaced" glyph ranges
|
||||
_usedGlyphRanges.erase((uintptr_t)it->second.data());
|
||||
// probably automatically gets *moved* but to make our intention more clear
|
||||
_eraseGlyphRanges.push_back(std::move(it->second));
|
||||
}
|
||||
it = _glyphRanges.emplace(key, ranges).first; // _glyphRanges[key] = ranges;
|
||||
if (ranges.empty())
|
||||
it->second.push_back(0);
|
||||
// the `addFont` will call `ImGui_ImplAx_SetDeviceObjectsDirty` if everything is okay,
|
||||
// no need to call it if no font is using the glyph ranges...
|
||||
return it->second.data();
|
||||
}
|
||||
|
||||
void ImGuiPresenter::removeGlyphRanges(std::string_view key)
|
||||
{
|
||||
auto removeGlyphRange = _glyphRanges.find(key);
|
||||
if (removeGlyphRange == _glyphRanges.end())
|
||||
return;
|
||||
|
||||
auto usedCount = _usedGlyphRanges.size();
|
||||
_usedGlyphRanges.erase((uintptr_t)removeGlyphRange->second.data());
|
||||
_eraseGlyphRanges.push_back(std::move(removeGlyphRange->second));
|
||||
_glyphRanges.erase(key);
|
||||
|
||||
// update the fonts to not use the glyph ranges since user wants to remove it for some reason..
|
||||
if (_usedGlyphRanges.size() != usedCount)
|
||||
ImGui_ImplAx_SetDeviceObjectsDirty();
|
||||
}
|
||||
|
||||
void ImGuiPresenter::clearGlyphRanges()
|
||||
{
|
||||
auto usedCount = _usedGlyphRanges.size();
|
||||
for (auto& glyphRange : _glyphRanges)
|
||||
{
|
||||
_usedGlyphRanges.erase((uintptr_t)glyphRange.second.data());
|
||||
_eraseGlyphRanges.push_back(std::move(glyphRange.second));
|
||||
}
|
||||
_glyphRanges.clear();
|
||||
|
||||
if (_usedGlyphRanges.size() != usedCount)
|
||||
ImGui_ImplAx_SetDeviceObjectsDirty();
|
||||
}
|
||||
|
||||
void ImGuiPresenter::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end)
|
||||
{
|
||||
if (!dst || !src || start > end)
|
||||
|
@ -901,4 +1035,31 @@ int ImGuiPresenter::getCCRefId(Object* p)
|
|||
return (int)hash;
|
||||
}
|
||||
|
||||
std::string_view ImGuiPresenter::getGlyphRangesId(GLYPH_RANGES glyphRanges)
|
||||
{
|
||||
switch (glyphRanges)
|
||||
{
|
||||
case GLYPH_RANGES::DEFAULT:
|
||||
return GLYPH_RANGES_DEFAULT_ID;
|
||||
case GLYPH_RANGES::GREEK:
|
||||
return GLYPH_RANGES_GREEK_ID;
|
||||
case GLYPH_RANGES::KOREAN:
|
||||
return GLYPH_RANGES_KOREAN_ID;
|
||||
case GLYPH_RANGES::CHINESE_GENERAL:
|
||||
return GLYPH_RANGES_CHINESE_GENERAL_ID;
|
||||
case GLYPH_RANGES::CHINESE_FULL:
|
||||
return GLYPH_RANGES_CHINESE_FULL_ID;
|
||||
case GLYPH_RANGES::JAPANESE:
|
||||
return GLYPH_RANGES_JAPANESE_ID;
|
||||
case GLYPH_RANGES::CYRILLIC:
|
||||
return GLYPH_RANGES_CYRILLIC_ID;
|
||||
case GLYPH_RANGES::THAI:
|
||||
return GLYPH_RANGES_THAI_ID;
|
||||
case GLYPH_RANGES::VIETNAMESE:
|
||||
return GLYPH_RANGES_VIETNAMESE_ID;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
NS_AX_EXT_END
|
||||
|
|
|
@ -20,13 +20,33 @@ class ImGuiPresenter
|
|||
void cleanup();
|
||||
|
||||
public:
|
||||
enum class CHS_GLYPH_RANGE
|
||||
inline static const std::string_view GLYPH_RANGES_DEFAULT_ID = "__DEFAULT_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_GREEK_ID = "__GREEK_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_KOREAN_ID = "__KOREAN_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_CHINESE_GENERAL_ID = "__CHINESE_SIMPLIFIED_COMMON_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_CHINESE_FULL_ID = "__CHINESE_FULL_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_JAPANESE_ID = "__JAPANESE_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_CYRILLIC_ID = "__CYRILLIC_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_THAI_ID = "__THAI_GLYPH__";
|
||||
inline static const std::string_view GLYPH_RANGES_VIETNAMESE_ID = "__VIETNAMESE_GLYPH__";
|
||||
|
||||
// predefined glyph ranges by imgui
|
||||
enum class GLYPH_RANGES
|
||||
{
|
||||
NONE,
|
||||
GENERAL,
|
||||
FULL
|
||||
DEFAULT,
|
||||
GREEK,
|
||||
KOREAN,
|
||||
CHINESE_GENERAL,
|
||||
CHINESE_FULL,
|
||||
JAPANESE,
|
||||
CYRILLIC,
|
||||
THAI,
|
||||
VIETNAMESE
|
||||
};
|
||||
|
||||
static std::string_view getGlyphRangesId(GLYPH_RANGES glyphRanges);
|
||||
|
||||
enum
|
||||
{
|
||||
DEFAULT_FONT_SIZE = 13 // see imgui.cpp
|
||||
|
@ -57,8 +77,30 @@ public:
|
|||
/// <param name="fontFile"></param>
|
||||
/// <param name="glyphRange"></param>
|
||||
void addFont(std::string_view fontFile,
|
||||
float fontSize = DEFAULT_FONT_SIZE,
|
||||
CHS_GLYPH_RANGE glyphRange = CHS_GLYPH_RANGE::NONE);
|
||||
float fontSize = DEFAULT_FONT_SIZE,
|
||||
GLYPH_RANGES glyphRange = GLYPH_RANGES::NONE);
|
||||
/// <summary>
|
||||
/// Add ImGui font with contentZoomFactor and use pre-existing glyph range for the specified font
|
||||
/// </summary>
|
||||
/// <param name="fontFile"></param>
|
||||
/// <param name="glyphRanges">The glyph range vector must end with 0 and it should be included in the size</param>
|
||||
void addFont(std::string_view fontFile, float fontSize, std::string_view glyphRangesId);
|
||||
/// <summary>
|
||||
/// Add ImGui font with contentZoomFactor and use specified custom glyph range for the specified font
|
||||
/// </summary>
|
||||
/// <param name="fontFile"></param>
|
||||
/// <param name="glyphRange">The glyph range vector must end with 0 and it should be included in the size</param>
|
||||
void addFont(std::string_view fontFile, float fontSize, const std::vector<ImWchar>& glyphRanges);
|
||||
/// <summary>
|
||||
/// Add ImGui font with contentZoomFactor and use custom glyph range and specify a custom id
|
||||
/// </summary>
|
||||
/// <param name="fontFile"></param>
|
||||
/// <param name="glyphRangesId">Custom Lookup Id</param>
|
||||
/// <param name="glyphRanges">The glyph range vector must end with 0 and it should be included in the size</param>
|
||||
void addFont(std::string_view fontFile,
|
||||
float fontSize,
|
||||
std::string_view glyphRangesId,
|
||||
const std::vector<ImWchar>& glyphRanges);
|
||||
void removeFont(std::string_view fontFile);
|
||||
void clearFonts();
|
||||
|
||||
|
@ -124,7 +166,10 @@ public:
|
|||
static void setLabelColor(Label* label, bool disabled = false);
|
||||
static void setLabelColor(Label* label, ImGuiCol col);
|
||||
|
||||
ImWchar* addGlyphRanges(GLYPH_RANGES glyphRange);
|
||||
ImWchar* addGlyphRanges(std::string_view key, const std::vector<ImWchar>& ranges);
|
||||
void removeGlyphRanges(std::string_view key);
|
||||
void clearGlyphRanges();
|
||||
static void mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end);
|
||||
int getCCRefId(Object* p);
|
||||
|
||||
|
@ -151,7 +196,11 @@ private:
|
|||
std::unordered_map<Object*, int> usedCCRefIdMap;
|
||||
// cocos objects should be retained until next frame
|
||||
Vector<Object*> usedCCRef;
|
||||
hlookup::string_map<std::vector<ImWchar>> glyphRanges;
|
||||
|
||||
hlookup::string_map<std::vector<ImWchar>> _glyphRanges;
|
||||
std::unordered_set<uintptr_t> _usedGlyphRanges; // there should be one intance of "each glyph ranges"
|
||||
// temporarily stores the current erased/replaced ranges, gets cleared in the next `loadCustomFonts` interation
|
||||
std::vector<std::vector<ImWchar>> _eraseGlyphRanges;
|
||||
|
||||
float _contentZoomFactor = 1.0f;
|
||||
|
||||
|
@ -162,7 +211,8 @@ private:
|
|||
struct FontInfo
|
||||
{
|
||||
float fontSize;
|
||||
CHS_GLYPH_RANGE glyphRange;
|
||||
ImWchar* glyphRanges;
|
||||
std::string glyphRangesId;
|
||||
};
|
||||
|
||||
hlookup::string_map<FontInfo> _fontsInfoMap;
|
||||
|
|
|
@ -9,6 +9,9 @@ Sync from https://github.com/Xrysnow/cocos2d-x-imgui and do a little changes
|
|||
* Use ```FOURCC``` for key of ImGui render loop
|
||||
* Add dpi scale support, use ```ImGuiPresenter::getInstance()->enableDPIScale();```
|
||||
* Easy font manager, stable API ```addFont,removeFont,clearFonts``` to manage ImGui fonts, with ImGui API, very hard to do correctly.
|
||||
* Easy to add/use custom or imgui pre-defined glyph ranges ```ImGuiPresenter::GLYPH_RANGES,addGlyphRanges,removeGlyphRanges```
|
||||
and then specify the glyph ranges id while calling `addFont`
|
||||
to use those with specific font.
|
||||
|
||||
## How to use
|
||||
```cpp
|
||||
|
@ -24,7 +27,7 @@ public:
|
|||
ImGuiPresenter::getInstance()->addFont(R"(C:\Windows\Fonts\msyh.ttc)");
|
||||
/* For Simplified Chinese support, please use:
|
||||
ImGuiPresenter::getInstance()->addFont(R"(C:\Windows\Fonts\msyh.ttc)", ImGuiPresenter::DEFAULT_FONT_SIZE,
|
||||
ImGuiPresenter::CHS_GLYPH_RANGE::GENERAL);
|
||||
ImGuiPresenter::GLYPH_RANGES::CHINESE_GENERAL);
|
||||
*/
|
||||
ImGuiPresenter::getInstance()->enableDPIScale(); // enable dpi scale for 4K display support, depends at least one valid ttf/ttc font was added.
|
||||
ImGuiPresenter::getInstance()->addRenderLoop("#im01", AX_CALLBACK_0(GameScene::onImGuiDraw, this), this);
|
||||
|
|
|
@ -177,9 +177,15 @@ void Inspector::setFontSize(float fontSize)
|
|||
_fontSize = fontSize;
|
||||
}
|
||||
|
||||
void Inspector::setFontGlyphId(std::string_view glyphId)
|
||||
{
|
||||
_fontGlyphId = std::string(glyphId);
|
||||
}
|
||||
|
||||
void Inspector::init()
|
||||
{
|
||||
_fontPath = "fonts/arial.ttf";
|
||||
_fontSize = ImGuiPresenter::DEFAULT_FONT_SIZE;
|
||||
|
||||
addPropertyHandler("__NODE__", std::make_unique<InspectorNodePropertyHandler>());
|
||||
addPropertyHandler("__SPRITE__", std::make_unique<InspectorSpritePropertyHandler>());
|
||||
|
@ -399,7 +405,7 @@ void Inspector::openForScene(Scene* target)
|
|||
}
|
||||
|
||||
auto* presenter = ImGuiPresenter::getInstance();
|
||||
presenter->addFont(FileUtils::getInstance()->fullPathForFilename(_fontPath), _fontSize);
|
||||
presenter->addFont(FileUtils::getInstance()->fullPathForFilename(_fontPath), _fontSize, _fontGlyphId);
|
||||
presenter->enableDPIScale();
|
||||
presenter->addRenderLoop("#insp", AX_CALLBACK_0(Inspector::mainLoop , this), target);
|
||||
}
|
||||
|
|
|
@ -65,10 +65,12 @@ class Inspector
|
|||
|
||||
void setAutoAddToScenes(bool autoAdd);
|
||||
|
||||
std::string_view getFontPath() { return _fontPath; }
|
||||
float getFontSize() { return _fontSize; }
|
||||
std::string_view getFontPath() const { return _fontPath; }
|
||||
float getFontSize() const { return _fontSize; }
|
||||
std::string_view getFontGlyphId() const { return _fontGlyphId; }
|
||||
void setFontPath(std::string_view fontPath);
|
||||
void setFontSize(float fontSize);
|
||||
void setFontGlyphId(std::string_view glyphId);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
@ -86,7 +88,8 @@ class Inspector
|
|||
|
||||
bool _autoAddToScenes = false;
|
||||
std::string _fontPath;
|
||||
float _fontSize = 13; // ImGuiPresenter.h
|
||||
float _fontSize;
|
||||
std::string _fontGlyphId;
|
||||
};
|
||||
|
||||
NS_AX_EXT_END
|
||||
|
|
|
@ -221,7 +221,7 @@ void SDFGen::open(ax::Scene* scene)
|
|||
ImGuiPresenter::getInstance()->addFont(defaultFontFile);
|
||||
/* For Simplified Chinese support, please use:
|
||||
ImGuiPresenter::getInstance()->addFont(R"(C:\Windows\Fonts\msyh.ttc)", ImGuiPresenter::DEFAULT_FONT_SIZE,
|
||||
ImGuiPresenter::CHS_GLYPH_RANGE::GENERAL);
|
||||
ImGuiPresenter::GLYPH_RANGES::CHINESE_GENERAL);
|
||||
*/
|
||||
ImGuiPresenter::getInstance()->enableDPIScale(); // enable dpi scale for 4K display support, depends at least one
|
||||
// valid ttf/ttc font was added.
|
||||
|
|
Loading…
Reference in New Issue