ImGUIEXT addRenderLoop support global without any target scene

This commit is contained in:
halx99 2020-09-07 23:21:15 +08:00
parent cde039b34b
commit 500e913517
2 changed files with 514 additions and 451 deletions

View File

@ -4,63 +4,122 @@
NS_CC_EXT_BEGIN NS_CC_EXT_BEGIN
static uint32_t fourccValue(const std::string& str) { static uint32_t fourccValue(const std::string& str) {
if (str.empty() || str[0] != '#') return (uint32_t)-1; if (str.empty() || str[0] != '#') return (uint32_t)-1;
uint32_t value = 0; uint32_t value = 0;
memcpy(&value, str.c_str() + 1, std::min(sizeof(value), str.size() - 1)); memcpy(&value, str.c_str() + 1, std::min(sizeof(value), str.size() - 1));
return value; return value;
} }
// TODO: Rename to ImGuiEXTLayerBlock class ImGuiEXTEventTracker {
// Because it's only used for block event when ImGui::IsAnyWindowHovered() == 'true' public:
class ImGuiEXTRenderer : public Layer virtual ~ImGuiEXTEventTracker() {}
};
// Track scene event and check whether routed to the scene graph
class ImGuiEXTSceneEventTracker : public ImGuiEXTEventTracker
{ {
CC_CONSTRUCTOR_ACCESS: public:
bool initWithImGuiEXT() bool initWithScene(Scene* scene)
{ {
if (!Layer::init())
return false;
#ifdef CC_PLATFORM_PC #ifdef CC_PLATFORM_PC
// note: when at the first click to focus the window, this will not take effect _trackLayer = utils::newInstance<Layer>();
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [this](Touch* touch, Event*) -> bool {
if (!_visible)
return false;
return ImGui::IsAnyWindowHovered();
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
// add by halx99 // note: when at the first click to focus the window, this will not take effect
auto stopAnyMouse = [=](EventMouse* event) { auto listener = EventListenerTouchOneByOne::create();
if (ImGui::IsAnyWindowHovered()) { listener->setSwallowTouches(true);
event->stopPropagation(); listener->onTouchBegan = [this](Touch* touch, Event*) -> bool {
} return ImGui::IsAnyWindowHovered();
}; };
auto mouseListener = EventListenerMouse::create(); _trackLayer->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, _trackLayer);
mouseListener->onMouseDown = mouseListener->onMouseUp = stopAnyMouse;
_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this); // add by halx99
auto stopAnyMouse = [=](EventMouse* event) {
if (ImGui::IsAnyWindowHovered()) {
event->stopPropagation();
}
};
auto mouseListener = EventListenerMouse::create();
mouseListener->onMouseDown = mouseListener->onMouseUp = stopAnyMouse;
_trackLayer->getEventDispatcher()->addEventListenerWithSceneGraphPriority(mouseListener, _trackLayer);
scene->addChild(_trackLayer, INT_MAX);
#endif #endif
// add an empty sprite to avoid render problem // add an empty sprite to avoid render problem
// const auto sp = Sprite::create(); // const auto sp = Sprite::create();
// sp->setGlobalZOrder(1); // sp->setGlobalZOrder(1);
// sp->setOpacity(0); // sp->setOpacity(0);
// addChild(sp, 1); // addChild(sp, 1);
/* /*
* There a 3 choice for schedule frame for ImGui render loop * There a 3 choice for schedule frame for ImGui render loop
* a. at visit/draw to call beginFrame/endFrame, but at ImGui loop, we can't game object and add to Scene directly, will cause damage iterator * a. at visit/draw to call beginFrame/endFrame, but at ImGui loop, we can't game object and add to Scene directly, will cause damage iterator
* b. scheduleUpdate at onEnter to call beginFrame, at visit/draw to call endFrame, it's solve iterator damage problem, but when director is paused * b. scheduleUpdate at onEnter to call beginFrame, at visit/draw to call endFrame, it's solve iterator damage problem, but when director is paused
* the director will stop call 'update' function of Scheduler * the director will stop call 'update' function of Scheduler
* And need modify engine code to call _scheduler->update(_deltaTime) even director is paused, pass 0 for update * And need modify engine code to call _scheduler->update(_deltaTime) even director is paused, pass 0 for update
* c. Director::EVENT_BEFORE_DRAW call beginFrame, EVENT_AFTER_VISIT call endFrame * c. Director::EVENT_BEFORE_DRAW call beginFrame, EVENT_AFTER_VISIT call endFrame
*/ */
return true;
}
~ImGuiEXTRenderer() return true;
{ }
}
~ImGuiEXTSceneEventTracker()
{
#ifdef CC_PLATFORM_PC
if (_trackLayer) {
if (_trackLayer->getParent())
_trackLayer->removeFromParent();
_trackLayer->release();
}
#endif
}
private:
Layer* _trackLayer = nullptr;
};
class ImGuiEXTGlobalEventTracker : public ImGuiEXTEventTracker
{
static const int highestPriority = (std::numeric_limits<int>::min)();
public:
bool init()
{
#ifdef CC_PLATFORM_PC
// note: when at the first click to focus the window, this will not take effect
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
_touchListener = utils::newInstance<EventListenerTouchOneByOne>();
_touchListener->setSwallowTouches(true);
_touchListener->onTouchBegan = [this](Touch* touch, Event*) -> bool {
return ImGui::IsAnyWindowHovered();
};
eventDispatcher->addEventListenerWithFixedPriority(_touchListener, highestPriority);
// add by halx99
auto stopAnyMouse = [=](EventMouse* event) {
if (ImGui::IsAnyWindowHovered()) {
event->stopPropagation();
}
};
_mouseListener = utils::newInstance<EventListenerMouse>();
_mouseListener->onMouseDown = _mouseListener->onMouseUp = stopAnyMouse;
eventDispatcher->addEventListenerWithFixedPriority(_mouseListener, highestPriority);
#endif
return true;
}
~ImGuiEXTGlobalEventTracker() {
#ifdef CC_PLATFORM_PC
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeEventListener(_mouseListener);
eventDispatcher->removeEventListener(_touchListener);
_mouseListener->release();
_touchListener->release();
#endif
}
EventListenerTouchOneByOne* _touchListener = nullptr;
EventListenerMouse* _mouseListener = nullptr;
}; };
static ImGuiEXT* _instance = nullptr; static ImGuiEXT* _instance = nullptr;
@ -68,400 +127,404 @@ std::function<void(ImGuiEXT*)> ImGuiEXT::_onInit;
void ImGuiEXT::init() void ImGuiEXT::init()
{ {
ImGui_ImplCocos2dx_Init(true); ImGui_ImplCocos2dx_Init(true);
ImGui::StyleColorsClassic(); ImGui::StyleColorsClassic();
auto eventDispatcher = Director::getInstance()->getEventDispatcher(); auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->addCustomEventListener(Director::EVENT_BEFORE_DRAW, [=](EventCustom*) { beginFrame(); }); eventDispatcher->addCustomEventListener(Director::EVENT_BEFORE_DRAW, [=](EventCustom*) { beginFrame(); });
eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_VISIT, [=](EventCustom*) { endFrame(); }); eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_VISIT, [=](EventCustom*) { endFrame(); });
} }
ImGuiEXT* ImGuiEXT::getInstance() ImGuiEXT* ImGuiEXT::getInstance()
{ {
if(_instance == nullptr) if (_instance == nullptr)
{ {
_instance = new ImGuiEXT(); _instance = new ImGuiEXT();
_instance->init(); _instance->init();
if (_onInit) if (_onInit)
_onInit(_instance); _onInit(_instance);
} }
return _instance; return _instance;
} }
void ImGuiEXT::destroyInstance() void ImGuiEXT::destroyInstance()
{ {
if (_instance) if (_instance)
{ {
auto eventDispatcher = Director::getInstance()->getEventDispatcher(); auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT); eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT);
eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW); eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW);
ImGui_ImplCocos2dx_Shutdown(); ImGui_ImplCocos2dx_Shutdown();
delete _instance; delete _instance;
_instance = nullptr; _instance = nullptr;
} }
} }
void ImGuiEXT::setOnInit(const std::function<void(ImGuiEXT*)>& callBack) void ImGuiEXT::setOnInit(const std::function<void(ImGuiEXT*)>& callBack)
{ {
_onInit = callBack; _onInit = callBack;
} }
float ImGuiEXT::scaleAllByDPI(float userScale) float ImGuiEXT::scaleAllByDPI(float userScale)
{ {
// Gets scale // Gets scale
float xscale = 1.0f; float xscale = 1.0f;
glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, nullptr); glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, nullptr);
auto zoomFactor = userScale * xscale; auto zoomFactor = userScale * xscale;
auto imFonts = ImGui::GetIO().Fonts; auto imFonts = ImGui::GetIO().Fonts;
// clear before add new font // clear before add new font
auto fontConf = imFonts->ConfigData; // copy font config data auto fontConf = imFonts->ConfigData; // copy font config data
if (zoomFactor != _contentZoomFactor) { if (zoomFactor != _contentZoomFactor) {
for (auto& fontConf : imFonts->ConfigData) for (auto& fontConf : imFonts->ConfigData)
{ {
fontConf.SizePixels = (fontConf.SizePixels / _contentZoomFactor) * zoomFactor; fontConf.SizePixels = (fontConf.SizePixels / _contentZoomFactor) * zoomFactor;
} }
// Destory font informations, let implcocos2dx recreate at newFrame // Destory font informations, let implcocos2dx recreate at newFrame
ImGui_ImplCocos2dx_DestroyDeviceObjects(); ImGui_ImplCocos2dx_DestroyDeviceObjects();
ImGui::GetStyle().ScaleAllSizes(zoomFactor); ImGui::GetStyle().ScaleAllSizes(zoomFactor);
_contentZoomFactor = zoomFactor; _contentZoomFactor = zoomFactor;
} }
return zoomFactor; return zoomFactor;
} }
void ImGuiEXT::addFont(const std::string& fontFile, float fontSize, CHS_GLYPH_RANGE glyphRange) void ImGuiEXT::addFont(const std::string& fontFile, float fontSize, CHS_GLYPH_RANGE glyphRange)
{ {
auto imFonts = ImGui::GetIO().Fonts; auto imFonts = ImGui::GetIO().Fonts;
const ImWchar* imChars = nullptr; const ImWchar* imChars = nullptr;
switch (glyphRange) { switch (glyphRange) {
case CHS_GLYPH_RANGE::GENERAL: case CHS_GLYPH_RANGE::GENERAL:
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon(); imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
break; break;
case CHS_GLYPH_RANGE::FULL: case CHS_GLYPH_RANGE::FULL:
imChars = imFonts->GetGlyphRangesChineseFull(); imChars = imFonts->GetGlyphRangesChineseFull();
break; break;
} }
imFonts->AddFontFromFileTTF(fontFile.c_str(), fontSize * _contentZoomFactor, nullptr, imChars); imFonts->AddFontFromFileTTF(fontFile.c_str(), fontSize * _contentZoomFactor, nullptr, imChars);
} }
void ImGuiEXT::clearFonts() void ImGuiEXT::clearFonts()
{ {
ImGui::GetIO().Fonts->Clear(); ImGui::GetIO().Fonts->Clear();
} }
/* /*
* begin ImGui frame and draw ImGui stubs * begin ImGui frame and draw ImGui stubs
*/ */
void ImGuiEXT::beginFrame() void ImGuiEXT::beginFrame()
{ {
// create frame // create frame
ImGui_ImplCocos2dx_NewFrame(); ImGui_ImplCocos2dx_NewFrame();
// draw all gui // draw all gui
this->update(); this->update();
// render // render
ImGui::Render(); ImGui::Render();
} }
/* /*
* flush ImGui draw data to engine * flush ImGui draw data to engine
*/ */
void ImGuiEXT::endFrame() { void ImGuiEXT::endFrame() {
ImGui_ImplCocos2dx_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplCocos2dx_RenderDrawData(ImGui::GetDrawData());
ImGui_ImplCocos2dx_RenderPlatform(); ImGui_ImplCocos2dx_RenderPlatform();
} }
void ImGuiEXT::update() void ImGuiEXT::update()
{ // drived by ImGuiEXTRenderer { // drived by ImGuiEXTRenderer
// clear things from last frame // clear things from last frame
usedCCRefIdMap.clear(); usedCCRefIdMap.clear();
usedCCRef.clear(); usedCCRef.clear();
// drawing commands // drawing commands
for (auto& pipline : _renderPiplines) for (auto& pipline : _renderPiplines)
pipline.second.frame(); pipline.second.frame();
// commands will be processed after update // commands will be processed after update
} }
bool ImGuiEXT::addRenderLoop(const std::string& id, Scene* scene, std::function<void()> onFrame) bool ImGuiEXT::addRenderLoop(const std::string& id, std::function<void()> func, Scene* target)
{ {
// TODO: check whether exist // TODO: check whether exist
auto fourccId = fourccValue(id); auto fourccId = fourccValue(id);
if (_renderPiplines.find(fourccId) != _renderPiplines.end()) if (_renderPiplines.find(fourccId) != _renderPiplines.end())
{ {
return false; return false;
} }
auto renderer = utils::newInstance<ImGuiEXTRenderer>(&ImGuiEXTRenderer::initWithImGuiEXT); ImGuiEXTEventTracker* tracker;
scene->addChild(renderer, INT_MAX, fourccId); if (target)
_renderPiplines.emplace(fourccId, RenderPipline{ renderer, std::move(onFrame) }); tracker = utils::newInstance<ImGuiEXTSceneEventTracker>(&ImGuiEXTSceneEventTracker::initWithScene, target);
else
tracker = utils::newInstance<ImGuiEXTGlobalEventTracker>();
return true; if (tracker) {
_renderPiplines.emplace(fourccId, RenderPipline{ tracker, std::move(func) });
return true;
}
return false;
} }
void ImGuiEXT::removeRenderLoop(const std::string& id) void ImGuiEXT::removeRenderLoop(const std::string& id)
{ {
auto fourccId = fourccValue(id); auto fourccId = fourccValue(id);
const auto iter = _renderPiplines.find(fourccId); const auto iter = _renderPiplines.find(fourccId);
if (iter != _renderPiplines.end()) { if (iter != _renderPiplines.end()) {
auto renderer = iter->second.renderer; auto tracker = iter->second.tracker;
if (renderer->getParent()) delete tracker;
renderer->removeFromParent(); _renderPiplines.erase(iter);
renderer->release(); }
_renderPiplines.erase(iter);
}
} }
static std::tuple<ImVec2, ImVec2> getTextureUV(Sprite* sp) static std::tuple<ImVec2, ImVec2> getTextureUV(Sprite* sp)
{ {
ImVec2 uv0, uv1; ImVec2 uv0, uv1;
if (!sp || !sp->getTexture()) if (!sp || !sp->getTexture())
return { uv0,uv1 }; return { uv0,uv1 };
const auto rect = sp->getTextureRect(); const auto rect = sp->getTextureRect();
const auto tex = sp->getTexture(); const auto tex = sp->getTexture();
const float atlasWidth = (float)tex->getPixelsWide(); const float atlasWidth = (float)tex->getPixelsWide();
const float atlasHeight = (float)tex->getPixelsHigh(); const float atlasHeight = (float)tex->getPixelsHigh();
uv0.x = rect.origin.x / atlasWidth; uv0.x = rect.origin.x / atlasWidth;
uv0.y = rect.origin.y / atlasHeight; uv0.y = rect.origin.y / atlasHeight;
uv1.x = (rect.origin.x + rect.size.width) / atlasWidth; uv1.x = (rect.origin.x + rect.size.width) / atlasWidth;
uv1.y = (rect.origin.y + rect.size.height) / atlasHeight; uv1.y = (rect.origin.y + rect.size.height) / atlasHeight;
return { uv0,uv1 }; return { uv0,uv1 };
} }
void ImGuiEXT::image(Texture2D* tex, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, void ImGuiEXT::image(Texture2D* tex, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1,
const ImVec4& tint_col, const ImVec4& border_col) const ImVec4& tint_col, const ImVec4& border_col)
{ {
if (!tex) if (!tex)
return; return;
auto size_ = size; auto size_ = size;
if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); if (size_.x <= 0.f) size_.x = tex->getPixelsWide();
if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); if (size_.y <= 0.f) size_.y = tex->getPixelsHigh();
ImGui::PushID(getCCRefId(tex)); ImGui::PushID(getCCRefId(tex));
ImGui::Image((ImTextureID)tex, size_, uv0, uv1, tint_col, border_col); ImGui::Image((ImTextureID)tex, size_, uv0, uv1, tint_col, border_col);
ImGui::PopID(); ImGui::PopID();
} }
void ImGuiEXT::image(Sprite* sprite, const ImVec2& size, const ImVec4& tint_col, const ImVec4& border_col) void ImGuiEXT::image(Sprite* sprite, const ImVec2& size, const ImVec4& tint_col, const ImVec4& border_col)
{ {
if (!sprite || !sprite->getTexture()) if (!sprite || !sprite->getTexture())
return; return;
auto size_ = size; auto size_ = size;
const auto rect = sprite->getTextureRect(); const auto rect = sprite->getTextureRect();
if (size_.x <= 0.f) size_.x = rect.size.width; if (size_.x <= 0.f) size_.x = rect.size.width;
if (size_.y <= 0.f) size_.y = rect.size.height; if (size_.y <= 0.f) size_.y = rect.size.height;
ImVec2 uv0, uv1; ImVec2 uv0, uv1;
std::tie(uv0, uv1) = getTextureUV(sprite); std::tie(uv0, uv1) = getTextureUV(sprite);
ImGui::PushID(getCCRefId(sprite)); ImGui::PushID(getCCRefId(sprite));
ImGui::Image((ImTextureID)sprite->getTexture(), size_, uv0, uv1, tint_col, border_col); ImGui::Image((ImTextureID)sprite->getTexture(), size_, uv0, uv1, tint_col, border_col);
ImGui::PopID(); ImGui::PopID();
} }
bool ImGuiEXT::imageButton(Texture2D* tex, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, bool ImGuiEXT::imageButton(Texture2D* tex, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1,
int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
{ {
if (!tex) if (!tex)
return false; return false;
auto size_ = size; auto size_ = size;
if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); if (size_.x <= 0.f) size_.x = tex->getPixelsWide();
if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); if (size_.y <= 0.f) size_.y = tex->getPixelsHigh();
ImGui::PushID(getCCRefId(tex)); ImGui::PushID(getCCRefId(tex));
const auto ret = ImGui::ImageButton((ImTextureID)tex, const auto ret = ImGui::ImageButton((ImTextureID)tex,
size_, uv0, uv1, frame_padding, bg_col, tint_col); size_, uv0, uv1, frame_padding, bg_col, tint_col);
ImGui::PopID(); ImGui::PopID();
return ret; return ret;
} }
bool ImGuiEXT::imageButton(Sprite* sprite, const ImVec2& size, int frame_padding, const ImVec4& bg_col, bool ImGuiEXT::imageButton(Sprite* sprite, const ImVec2& size, int frame_padding, const ImVec4& bg_col,
const ImVec4& tint_col) const ImVec4& tint_col)
{ {
if (!sprite || !sprite->getTexture()) if (!sprite || !sprite->getTexture())
return false; return false;
auto size_ = size; auto size_ = size;
const auto rect = sprite->getTextureRect(); const auto rect = sprite->getTextureRect();
if (size_.x <= 0.f) size_.x = rect.size.width; if (size_.x <= 0.f) size_.x = rect.size.width;
if (size_.y <= 0.f) size_.y = rect.size.height; if (size_.y <= 0.f) size_.y = rect.size.height;
ImVec2 uv0, uv1; ImVec2 uv0, uv1;
std::tie(uv0, uv1) = getTextureUV(sprite); std::tie(uv0, uv1) = getTextureUV(sprite);
ImGui::PushID(getCCRefId(sprite)); ImGui::PushID(getCCRefId(sprite));
const auto ret = ImGui::ImageButton((ImTextureID)sprite->getTexture(), const auto ret = ImGui::ImageButton((ImTextureID)sprite->getTexture(),
size_, uv0, uv1, frame_padding, bg_col, tint_col); size_, uv0, uv1, frame_padding, bg_col, tint_col);
ImGui::PopID(); ImGui::PopID();
return ret; return ret;
} }
void ImGuiEXT::node(Node* node, const ImVec4& tint_col, const ImVec4& border_col) void ImGuiEXT::node(Node* node, const ImVec4& tint_col, const ImVec4& border_col)
{ {
if (!node) if (!node)
return; return;
const auto size = node->getContentSize(); const auto size = node->getContentSize();
const auto pos = ImGui::GetCursorScreenPos(); const auto pos = ImGui::GetCursorScreenPos();
Mat4 tr; Mat4 tr;
tr.m[5] = -1; tr.m[5] = -1;
tr.m[12] = pos.x; tr.m[12] = pos.x;
tr.m[13] = pos.y + size.height; tr.m[13] = pos.y + size.height;
if (border_col.w > 0.f) if (border_col.w > 0.f)
{ {
tr.m[12] += 1; tr.m[12] += 1;
tr.m[13] += 1; tr.m[13] += 1;
} }
node->setNodeToParentTransform(tr); node->setNodeToParentTransform(tr);
ImGui::PushID(getCCRefId(node)); ImGui::PushID(getCCRefId(node));
ImGui::Image((ImTextureID)node, ImGui::Image((ImTextureID)node,
ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col);
ImGui::PopID(); ImGui::PopID();
} }
bool ImGuiEXT::nodeButton(Node* node, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) bool ImGuiEXT::nodeButton(Node* node, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
{ {
if (!node) if (!node)
return false; return false;
const auto size = node->getContentSize(); const auto size = node->getContentSize();
const auto pos = ImGui::GetCursorScreenPos(); const auto pos = ImGui::GetCursorScreenPos();
Mat4 tr; Mat4 tr;
tr.m[5] = -1; tr.m[5] = -1;
tr.m[12] = pos.x; tr.m[12] = pos.x;
tr.m[13] = pos.y + size.height; tr.m[13] = pos.y + size.height;
if (frame_padding >= 0) if (frame_padding >= 0)
{ {
tr.m[12] += (float)frame_padding; tr.m[12] += (float)frame_padding;
tr.m[13] += (float)frame_padding; tr.m[13] += (float)frame_padding;
} }
else else
{ {
tr.m[12] += ImGui::GetStyle().FramePadding.x; tr.m[12] += ImGui::GetStyle().FramePadding.x;
tr.m[13] += ImGui::GetStyle().FramePadding.y; tr.m[13] += ImGui::GetStyle().FramePadding.y;
} }
node->setNodeToParentTransform(tr); node->setNodeToParentTransform(tr);
ImGui::PushID(getCCRefId(node)); ImGui::PushID(getCCRefId(node));
const auto ret = ImGui::ImageButton((ImTextureID)node, const auto ret = ImGui::ImageButton((ImTextureID)node,
ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), frame_padding, bg_col, tint_col); ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), frame_padding, bg_col, tint_col);
ImGui::PopID(); ImGui::PopID();
return ret; return ret;
} }
std::tuple<ImTextureID, int> ImGuiEXT::useTexture(Texture2D* texture) std::tuple<ImTextureID, int> ImGuiEXT::useTexture(Texture2D* texture)
{ {
if (!texture) if (!texture)
return { nullptr,0 }; return { nullptr,0 };
return { (ImTextureID)texture,getCCRefId(texture) }; return { (ImTextureID)texture,getCCRefId(texture) };
} }
std::tuple<ImTextureID, ImVec2, ImVec2, int> ImGuiEXT::useSprite(Sprite* sprite) std::tuple<ImTextureID, ImVec2, ImVec2, int> ImGuiEXT::useSprite(Sprite* sprite)
{ {
if (!sprite || !sprite->getTexture()) if (!sprite || !sprite->getTexture())
return { nullptr,{},{},0 }; return { nullptr,{},{},0 };
ImVec2 uv0, uv1; ImVec2 uv0, uv1;
std::tie(uv0, uv1) = getTextureUV(sprite); std::tie(uv0, uv1) = getTextureUV(sprite);
return { (ImTextureID)sprite->getTexture(),uv0,uv1,getCCRefId(sprite) }; return { (ImTextureID)sprite->getTexture(),uv0,uv1,getCCRefId(sprite) };
} }
std::tuple<ImTextureID, ImVec2, ImVec2, int> ImGuiEXT::useNode(Node* node, const ImVec2& pos) std::tuple<ImTextureID, ImVec2, ImVec2, int> ImGuiEXT::useNode(Node* node, const ImVec2& pos)
{ {
if (!node) if (!node)
return { nullptr,{},{},0 }; return { nullptr,{},{},0 };
const auto size = node->getContentSize(); const auto size = node->getContentSize();
Mat4 tr; Mat4 tr;
tr.m[5] = -1; tr.m[5] = -1;
tr.m[12] = pos.x; tr.m[12] = pos.x;
tr.m[13] = pos.y + size.height; tr.m[13] = pos.y + size.height;
node->setNodeToParentTransform(tr); node->setNodeToParentTransform(tr);
return { (ImTextureID)node,pos,ImVec2(pos.x + size.width,pos.y + size.height),getCCRefId(node) }; return { (ImTextureID)node,pos,ImVec2(pos.x + size.width,pos.y + size.height),getCCRefId(node) };
} }
void ImGuiEXT::setNodeColor(Node* node, const ImVec4& col) void ImGuiEXT::setNodeColor(Node* node, const ImVec4& col)
{ {
if (node) if (node)
{ {
node->setColor({ uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255) }); node->setColor({ uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255) });
node->setOpacity(uint8_t(col.w * 255)); node->setOpacity(uint8_t(col.w * 255));
} }
} }
void ImGuiEXT::setNodeColor(Node* node, ImGuiCol col) void ImGuiEXT::setNodeColor(Node* node, ImGuiCol col)
{ {
if (node && 0 <= col && col < ImGuiCol_COUNT) if (node && 0 <= col && col < ImGuiCol_COUNT)
setNodeColor(node, ImGui::GetStyleColorVec4(col)); setNodeColor(node, ImGui::GetStyleColorVec4(col));
} }
void ImGuiEXT::setLabelColor(Label* label, const ImVec4& col) void ImGuiEXT::setLabelColor(Label* label, const ImVec4& col)
{ {
if (label) if (label)
{ {
label->setTextColor( label->setTextColor(
{ uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255),uint8_t(col.w * 255) }); { uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255),uint8_t(col.w * 255) });
} }
} }
void ImGuiEXT::setLabelColor(Label* label, bool disabled) void ImGuiEXT::setLabelColor(Label* label, bool disabled)
{ {
if (label) if (label)
setLabelColor(label, ImGui::GetStyleColorVec4(disabled ? ImGuiCol_TextDisabled : ImGuiCol_Text)); setLabelColor(label, ImGui::GetStyleColorVec4(disabled ? ImGuiCol_TextDisabled : ImGuiCol_Text));
} }
void ImGuiEXT::setLabelColor(Label* label, ImGuiCol col) void ImGuiEXT::setLabelColor(Label* label, ImGuiCol col)
{ {
if (label && 0 <= col && col < ImGuiCol_COUNT) if (label && 0 <= col && col < ImGuiCol_COUNT)
setLabelColor(label, ImGui::GetStyleColorVec4(col)); setLabelColor(label, ImGui::GetStyleColorVec4(col));
} }
ImWchar* ImGuiEXT::addGlyphRanges(const std::string& key, const std::vector<ImWchar>& ranges) ImWchar* ImGuiEXT::addGlyphRanges(const std::string& key, const std::vector<ImWchar>& ranges)
{ {
auto it = glyphRanges.find(key); auto it = glyphRanges.find(key);
// the pointer must be persistant, do not replace // the pointer must be persistant, do not replace
if (it != glyphRanges.end()) if (it != glyphRanges.end())
return it->second.data(); return it->second.data();
glyphRanges[key] = ranges; glyphRanges[key] = ranges;
if (ranges.empty()) if (ranges.empty())
glyphRanges[key].push_back(0); glyphRanges[key].push_back(0);
return glyphRanges[key].data(); return glyphRanges[key].data();
} }
void ImGuiEXT::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end) void ImGuiEXT::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end)
{ {
if (!dst || !src || start > end) if (!dst || !src || start > end)
return; return;
for (auto i = start; i <= end; ++i) for (auto i = start; i <= end; ++i)
{ {
const auto g = src->FindGlyphNoFallback(i); const auto g = src->FindGlyphNoFallback(i);
if (g) if (g)
{ {
// TODO // TODO
// dst->AddGlyph(g->Codepoint, g->X0, g->Y0, g->X1, g->Y1, g->U0, g->V0, g->U1, g->V1, g->AdvanceX); // dst->AddGlyph(g->Codepoint, g->X0, g->Y0, g->X1, g->Y1, g->U0, g->V0, g->U1, g->V1, g->AdvanceX);
} }
} }
dst->BuildLookupTable(); dst->BuildLookupTable();
} }
int ImGuiEXT::getCCRefId(Ref* p) int ImGuiEXT::getCCRefId(Ref* p)
{ {
int id = 0; int id = 0;
const auto it = usedCCRefIdMap.find(p); const auto it = usedCCRefIdMap.find(p);
if (it == usedCCRefIdMap.end()) if (it == usedCCRefIdMap.end())
{ {
usedCCRefIdMap[p] = 0; usedCCRefIdMap[p] = 0;
usedCCRef.pushBack(p); usedCCRef.pushBack(p);
} }
else else
id = ++it->second; id = ++it->second;
// BKDR hash // BKDR hash
constexpr unsigned int seed = 131; constexpr unsigned int seed = 131;
unsigned int hash = 0; unsigned int hash = 0;
for (auto i = 0u; i < sizeof(void*); ++i) for (auto i = 0u; i < sizeof(void*); ++i)
hash = hash * seed + ((const char*)&p)[i]; hash = hash * seed + ((const char*)&p)[i];
for (auto i = 0u; i < sizeof(int); ++i) for (auto i = 0u; i < sizeof(int); ++i)
hash = hash * seed + ((const char*)&id)[i]; hash = hash * seed + ((const char*)&id)[i];
return (int)hash; return (int)hash;
} }
#if defined(HAVE_IMGUI_MARKDOWN) #if defined(HAVE_IMGUI_MARKDOWN)
@ -473,64 +536,64 @@ static ImGui::MarkdownImageData ImGuiMarkdownInvalidImageData = { false, false,
void MarkdownLinkCallback(ImGui::MarkdownLinkCallbackData data) void MarkdownLinkCallback(ImGui::MarkdownLinkCallbackData data)
{ {
if (ImGuiMarkdownLinkCallback) if (ImGuiMarkdownLinkCallback)
{ {
ImGuiMarkdownLinkCallback( ImGuiMarkdownLinkCallback(
{ data.text, (size_t)data.textLength }, { data.link, (size_t)data.linkLength }, data.isImage); { data.text, (size_t)data.textLength }, { data.link, (size_t)data.linkLength }, data.isImage);
} }
} }
ImGui::MarkdownImageData MarkdownImageCallback(ImGui::MarkdownLinkCallbackData data) ImGui::MarkdownImageData MarkdownImageCallback(ImGui::MarkdownLinkCallbackData data)
{ {
if (!data.isImage || !ImGuiMarkdownImageCallback) if (!data.isImage || !ImGuiMarkdownImageCallback)
return ImGuiMarkdownInvalidImageData; return ImGuiMarkdownInvalidImageData;
Sprite* sp; ImVec2 size; ImVec4 tint_col; ImVec4 border_col; Sprite* sp; ImVec2 size; ImVec4 tint_col; ImVec4 border_col;
std::tie(sp, size, tint_col, border_col) = ImGuiMarkdownImageCallback( std::tie(sp, size, tint_col, border_col) = ImGuiMarkdownImageCallback(
{ data.text, (size_t)data.textLength }, { data.text, (size_t)data.textLength },
{ data.link, (size_t)data.linkLength }); { data.link, (size_t)data.linkLength });
if(!sp || !sp->getTexture()) if (!sp || !sp->getTexture())
return ImGuiMarkdownInvalidImageData; return ImGuiMarkdownInvalidImageData;
auto size_ = size; auto size_ = size;
const auto rect = sp->getTextureRect(); const auto rect = sp->getTextureRect();
if (size_.x <= 0.f) size_.x = rect.size.width; if (size_.x <= 0.f) size_.x = rect.size.width;
if (size_.y <= 0.f) size_.y = rect.size.height; if (size_.y <= 0.f) size_.y = rect.size.height;
ImVec2 uv0, uv1; ImVec2 uv0, uv1;
std::tie(uv0, uv1) = getTextureUV(sp); std::tie(uv0, uv1) = getTextureUV(sp);
ImGuiEXT::getInstance()->getCCRefId(sp); ImGuiEXT::getInstance()->getCCRefId(sp);
return { true, true, (ImTextureID)sp->getTexture(), size_,uv0, uv1, tint_col, border_col }; return { true, true, (ImTextureID)sp->getTexture(), size_,uv0, uv1, tint_col, border_col };
} }
static std::string ImGuiMarkdownLinkIcon; static std::string ImGuiMarkdownLinkIcon;
static ImGui::MarkdownConfig ImGuiMarkdownConfig = { static ImGui::MarkdownConfig ImGuiMarkdownConfig = {
MarkdownLinkCallback, MarkdownImageCallback, "" }; MarkdownLinkCallback, MarkdownImageCallback, "" };
void ImGuiEXT::setMarkdownLinkCallback(const MdLinkCallback& f) void ImGuiEXT::setMarkdownLinkCallback(const MdLinkCallback& f)
{ {
ImGuiMarkdownLinkCallback = f; ImGuiMarkdownLinkCallback = f;
} }
void ImGuiEXT::setMarkdownImageCallback(const MdImageCallback& f) void ImGuiEXT::setMarkdownImageCallback(const MdImageCallback& f)
{ {
ImGuiMarkdownImageCallback = f; ImGuiMarkdownImageCallback = f;
} }
void ImGuiEXT::setMarkdownFont(int index, ImFont* font, bool seperator, float scale) void ImGuiEXT::setMarkdownFont(int index, ImFont* font, bool seperator, float scale)
{ {
if (index < 0 || index >= ImGui::MarkdownConfig::NUMHEADINGS) if (index < 0 || index >= ImGui::MarkdownConfig::NUMHEADINGS)
return; return;
ImGuiMarkdownConfig.headingFormats[index] = { font,seperator }; ImGuiMarkdownConfig.headingFormats[index] = { font,seperator };
ImGuiMarkdownConfig.headingScales[index] = scale; ImGuiMarkdownConfig.headingScales[index] = scale;
} }
void ImGuiEXT::setMarkdownLinkIcon(const std::string& icon) void ImGuiEXT::setMarkdownLinkIcon(const std::string& icon)
{ {
ImGuiMarkdownLinkIcon = icon; ImGuiMarkdownLinkIcon = icon;
ImGuiMarkdownConfig.linkIcon = ImGuiMarkdownLinkIcon.c_str(); ImGuiMarkdownConfig.linkIcon = ImGuiMarkdownLinkIcon.c_str();
} }
void ImGuiEXT::markdown(const std::string& content) void ImGuiEXT::markdown(const std::string& content)
{ {
ImGui::Markdown(content.c_str(), content.size(), ImGuiMarkdownConfig); ImGui::Markdown(content.c_str(), content.size(), ImGuiMarkdownConfig);
} }
#endif #endif

View File

@ -10,145 +10,145 @@
NS_CC_EXT_BEGIN NS_CC_EXT_BEGIN
class ImGuiEXTRenderer; class ImGuiEXTEventTracker;
class ImGuiEXT class ImGuiEXT
{ {
friend class ImGuiEXTRenderer; friend class ImGuiEXTRenderer;
void init(); void init();
public: public:
enum class CHS_GLYPH_RANGE { enum class CHS_GLYPH_RANGE {
NONE, NONE,
GENERAL, GENERAL,
FULL FULL
}; };
enum { enum {
DEFAULT_FONT_SIZE = 13 // see imgui.cpp DEFAULT_FONT_SIZE = 13 // see imgui.cpp
}; };
static ImGuiEXT* getInstance(); static ImGuiEXT* getInstance();
static void destroyInstance(); static void destroyInstance();
static void setOnInit(const std::function<void(ImGuiEXT*)>& callBack); static void setOnInit(const std::function<void(ImGuiEXT*)>& callBack);
/// <summary> /// <summary>
/// Scale ImGui with majorMoniter DPI scaling /// Scale ImGui with majorMoniter DPI scaling
/// </summary> /// </summary>
/// <param name="userScale">Usually is 1.0</param> /// <param name="userScale">Usually is 1.0</param>
/// <param name="fontFile">The full path of .ttc/.ttf file</param> /// <param name="fontFile">The full path of .ttc/.ttf file</param>
/// <returns>The final contentZoomFactor = userScale * dpiScale</returns> /// <returns>The final contentZoomFactor = userScale * dpiScale</returns>
float scaleAllByDPI(float userScale); float scaleAllByDPI(float userScale);
float getContentZoomFactor() const { return _contentZoomFactor; } float getContentZoomFactor() const { return _contentZoomFactor; }
/// <summary> /// <summary>
/// Add ImGui font with contentZoomFactor /// Add ImGui font with contentZoomFactor
/// </summary> /// </summary>
/// <param name="fontFile"></param> /// <param name="fontFile"></param>
/// <param name="glyphRange"></param> /// <param name="glyphRange"></param>
void addFont(const std::string& fontFile, float fontSize = DEFAULT_FONT_SIZE, CHS_GLYPH_RANGE glyphRange = CHS_GLYPH_RANGE::NONE); void addFont(const std::string& fontFile, float fontSize = DEFAULT_FONT_SIZE, CHS_GLYPH_RANGE glyphRange = CHS_GLYPH_RANGE::NONE);
void clearFonts(); void clearFonts();
/// <summary> /// <summary>
/// Add a ImGui render loop to specific scene /// Add a ImGui render loop to specific scene
/// </summary> /// </summary>
/// <param name="id">The FOURCC id of render loop, starts with '#', such as "#abcd"</id> /// <param name="id">The FOURCC id of render loop, starts with '#', such as "#abcd"</id>
/// <param name="target">the target scene to render ImGui</param> /// <param name="func">the ImGui render loop</param>
/// <param name="func">the ImGui render loop</param> /// <param name="target">The target scene to track event, nullptr for global, useful for global GM tools</param>
bool addRenderLoop(const std::string& id, Scene* target, std::function<void()> func); bool addRenderLoop(const std::string& id, std::function<void()> func, Scene* target);
/// <summary> /// <summary>
/// Remove ImGui render loop /// Remove ImGui render loop
/// </summary> /// </summary>
/// <param name="id">FOURCC starts with '#', such as "#abcd"</id> /// <param name="id">FOURCC starts with '#', such as "#abcd"</id>
void removeRenderLoop(const std::string& id); void removeRenderLoop(const std::string& id);
// imgui helper // imgui helper
void image( void image(
Texture2D* tex, Texture2D* tex,
const ImVec2& size, const ImVec2& size,
const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv0 = ImVec2(0, 0),
const ImVec2& uv1 = ImVec2(1, 1), const ImVec2& uv1 = ImVec2(1, 1),
const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1),
const ImVec4& border_col = ImVec4(0, 0, 0, 0)); const ImVec4& border_col = ImVec4(0, 0, 0, 0));
void image( void image(
Sprite* sprite, Sprite* sprite,
const ImVec2& size, const ImVec2& size,
const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1),
const ImVec4& border_col = ImVec4(0, 0, 0, 0)); const ImVec4& border_col = ImVec4(0, 0, 0, 0));
bool imageButton( bool imageButton(
Texture2D* tex, Texture2D* tex,
const ImVec2& size, const ImVec2& size,
const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv0 = ImVec2(0, 0),
const ImVec2& uv1 = ImVec2(1, 1), const ImVec2& uv1 = ImVec2(1, 1),
int frame_padding = -1, int frame_padding = -1,
const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& bg_col = ImVec4(0, 0, 0, 0),
const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
bool imageButton( bool imageButton(
Sprite* sprite, Sprite* sprite,
const ImVec2& size, const ImVec2& size,
int frame_padding = -1, int frame_padding = -1,
const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& bg_col = ImVec4(0, 0, 0, 0),
const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
void node( void node(
Node* node, Node* node,
const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1),
const ImVec4& border_col = ImVec4(0, 0, 0, 0)); const ImVec4& border_col = ImVec4(0, 0, 0, 0));
bool nodeButton( bool nodeButton(
Node* node, Node* node,
int frame_padding = -1, int frame_padding = -1,
const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& bg_col = ImVec4(0, 0, 0, 0),
const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); const ImVec4& tint_col = ImVec4(1, 1, 1, 1));
std::tuple<ImTextureID, int> useTexture(Texture2D* texture); std::tuple<ImTextureID, int> useTexture(Texture2D* texture);
std::tuple<ImTextureID, ImVec2, ImVec2, int> useSprite(Sprite* sprite); std::tuple<ImTextureID, ImVec2, ImVec2, int> useSprite(Sprite* sprite);
std::tuple<ImTextureID, ImVec2, ImVec2, int> useNode(Node* node, const ImVec2& pos); std::tuple<ImTextureID, ImVec2, ImVec2, int> useNode(Node* node, const ImVec2& pos);
static void setNodeColor(Node* node, const ImVec4& col); static void setNodeColor(Node* node, const ImVec4& col);
static void setNodeColor(Node* node, ImGuiCol col); static void setNodeColor(Node* node, ImGuiCol col);
static void setLabelColor(Label* label, const ImVec4& col); static void setLabelColor(Label* label, const ImVec4& col);
static void setLabelColor(Label* label, bool disabled = false); static void setLabelColor(Label* label, bool disabled = false);
static void setLabelColor(Label* label, ImGuiCol col); static void setLabelColor(Label* label, ImGuiCol col);
ImWchar* addGlyphRanges(const std::string& key, const std::vector<ImWchar>& ranges); ImWchar* addGlyphRanges(const std::string& key, const std::vector<ImWchar>& ranges);
static void mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end); static void mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end);
int getCCRefId(Ref* p); int getCCRefId(Ref* p);
#if defined(HAVE_IMGUI_MARKDOWN) #if defined(HAVE_IMGUI_MARKDOWN)
// markdown // markdown
using MdLinkCallback = std::function<void(const std::string&, const std::string&, bool)>; using MdLinkCallback = std::function<void(const std::string&, const std::string&, bool)>;
using MdImageCallback = std::function<std::tuple<Sprite*, ImVec2, ImVec4, ImVec4>(const std::string&, const std::string&)>; using MdImageCallback = std::function<std::tuple<Sprite*, ImVec2, ImVec4, ImVec4>(const std::string&, const std::string&)>;
void setMarkdownLinkCallback(const MdLinkCallback& f); void setMarkdownLinkCallback(const MdLinkCallback& f);
void setMarkdownImageCallback(const MdImageCallback& f); void setMarkdownImageCallback(const MdImageCallback& f);
void setMarkdownFont(int index, ImFont* font, bool seperator, float scale = 1.f); void setMarkdownFont(int index, ImFont* font, bool seperator, float scale = 1.f);
void setMarkdownLinkIcon(const std::string& icon); void setMarkdownLinkIcon(const std::string& icon);
void markdown(const std::string& content); void markdown(const std::string& content);
#endif #endif
private: private:
// perform draw ImGui stubs // perform draw ImGui stubs
void beginFrame(); void beginFrame();
void update(); void update();
void endFrame(); void endFrame();
private: private:
static std::function<void(ImGuiEXT*)> _onInit; static std::function<void(ImGuiEXT*)> _onInit;
struct RenderPipline {
ImGuiEXTRenderer* renderer;
std::function<void()> frame;
};
std::unordered_map<uint32_t, RenderPipline> _renderPiplines; struct RenderPipline {
ImGuiEXTEventTracker* tracker;
std::function<void()> frame;
};
std::unordered_map<Ref*, int> usedCCRefIdMap; std::unordered_map<uint32_t, RenderPipline> _renderPiplines;
// cocos objects should be retained until next frame
Vector<Ref*> usedCCRef;
std::unordered_map<std::string, std::vector<ImWchar>> glyphRanges;
float _contentZoomFactor = 1.0f; std::unordered_map<Ref*, int> usedCCRefIdMap;
// cocos objects should be retained until next frame
Vector<Ref*> usedCCRef;
std::unordered_map<std::string, std::vector<ImWchar>> glyphRanges;
float _contentZoomFactor = 1.0f;
}; };
NS_CC_EXT_END NS_CC_EXT_END