From 500e9135177e0ba980a1573c1433e96488cf0bb8 Mon Sep 17 00:00:00 2001 From: halx99 Date: Mon, 7 Sep 2020 23:21:15 +0800 Subject: [PATCH] ImGUIEXT addRenderLoop support global without any target scene --- extensions/ImGuiEXT/CCImGuiEXT.cpp | 741 ++++++++++++++++------------- extensions/ImGuiEXT/CCImGuiEXT.h | 224 ++++----- 2 files changed, 514 insertions(+), 451 deletions(-) diff --git a/extensions/ImGuiEXT/CCImGuiEXT.cpp b/extensions/ImGuiEXT/CCImGuiEXT.cpp index 6ad7b07313..73e53332af 100644 --- a/extensions/ImGuiEXT/CCImGuiEXT.cpp +++ b/extensions/ImGuiEXT/CCImGuiEXT.cpp @@ -4,63 +4,122 @@ NS_CC_EXT_BEGIN static uint32_t fourccValue(const std::string& str) { - if (str.empty() || str[0] != '#') return (uint32_t)-1; - uint32_t value = 0; - memcpy(&value, str.c_str() + 1, std::min(sizeof(value), str.size() - 1)); - return value; + if (str.empty() || str[0] != '#') return (uint32_t)-1; + uint32_t value = 0; + memcpy(&value, str.c_str() + 1, std::min(sizeof(value), str.size() - 1)); + return value; } -// TODO: Rename to ImGuiEXTLayerBlock -// Because it's only used for block event when ImGui::IsAnyWindowHovered() == 'true' -class ImGuiEXTRenderer : public Layer +class ImGuiEXTEventTracker { +public: + virtual ~ImGuiEXTEventTracker() {} +}; + +// Track scene event and check whether routed to the scene graph +class ImGuiEXTSceneEventTracker : public ImGuiEXTEventTracker { -CC_CONSTRUCTOR_ACCESS: - bool initWithImGuiEXT() - { - if (!Layer::init()) - return false; - +public: + bool initWithScene(Scene* scene) + { #ifdef CC_PLATFORM_PC - // note: when at the first click to focus the window, this will not take effect - 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); + _trackLayer = utils::newInstance(); - // add by halx99 - auto stopAnyMouse = [=](EventMouse* event) { - if (ImGui::IsAnyWindowHovered()) { - event->stopPropagation(); - } - }; - auto mouseListener = EventListenerMouse::create(); - mouseListener->onMouseDown = mouseListener->onMouseUp = stopAnyMouse; - _eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this); + // note: when at the first click to focus the window, this will not take effect + auto listener = EventListenerTouchOneByOne::create(); + listener->setSwallowTouches(true); + listener->onTouchBegan = [this](Touch* touch, Event*) -> bool { + return ImGui::IsAnyWindowHovered(); + }; + _trackLayer->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, _trackLayer); + + // 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 - // add an empty sprite to avoid render problem - // const auto sp = Sprite::create(); - // sp->setGlobalZOrder(1); - // sp->setOpacity(0); - // addChild(sp, 1); + // add an empty sprite to avoid render problem + // const auto sp = Sprite::create(); + // sp->setGlobalZOrder(1); + // sp->setOpacity(0); + // addChild(sp, 1); - /* - * 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 - * 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 - * 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 - */ - return true; - } + /* + * 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 + * 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 + * 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 + */ - ~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::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(); + _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(); + _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; @@ -68,400 +127,404 @@ std::function ImGuiEXT::_onInit; void ImGuiEXT::init() { - ImGui_ImplCocos2dx_Init(true); + ImGui_ImplCocos2dx_Init(true); - ImGui::StyleColorsClassic(); + ImGui::StyleColorsClassic(); - auto eventDispatcher = Director::getInstance()->getEventDispatcher(); - eventDispatcher->addCustomEventListener(Director::EVENT_BEFORE_DRAW, [=](EventCustom*) { beginFrame(); }); - eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_VISIT, [=](EventCustom*) { endFrame(); }); + auto eventDispatcher = Director::getInstance()->getEventDispatcher(); + eventDispatcher->addCustomEventListener(Director::EVENT_BEFORE_DRAW, [=](EventCustom*) { beginFrame(); }); + eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_VISIT, [=](EventCustom*) { endFrame(); }); } ImGuiEXT* ImGuiEXT::getInstance() { - if(_instance == nullptr) - { - _instance = new ImGuiEXT(); - _instance->init(); - if (_onInit) - _onInit(_instance); - } - return _instance; + if (_instance == nullptr) + { + _instance = new ImGuiEXT(); + _instance->init(); + if (_onInit) + _onInit(_instance); + } + return _instance; } void ImGuiEXT::destroyInstance() { - if (_instance) - { - auto eventDispatcher = Director::getInstance()->getEventDispatcher(); - eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT); - eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW); + if (_instance) + { + auto eventDispatcher = Director::getInstance()->getEventDispatcher(); + eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT); + eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW); - ImGui_ImplCocos2dx_Shutdown(); - delete _instance; - _instance = nullptr; - } + ImGui_ImplCocos2dx_Shutdown(); + delete _instance; + _instance = nullptr; + } } void ImGuiEXT::setOnInit(const std::function& callBack) { - _onInit = callBack; + _onInit = callBack; } float ImGuiEXT::scaleAllByDPI(float userScale) { - // Gets scale - float xscale = 1.0f; - glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, nullptr); - auto zoomFactor = userScale * xscale; + // Gets scale + float xscale = 1.0f; + glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, nullptr); + auto zoomFactor = userScale * xscale; - auto imFonts = ImGui::GetIO().Fonts; + auto imFonts = ImGui::GetIO().Fonts; - // clear before add new font - auto fontConf = imFonts->ConfigData; // copy font config data + // clear before add new font + auto fontConf = imFonts->ConfigData; // copy font config data - if (zoomFactor != _contentZoomFactor) { - for (auto& fontConf : imFonts->ConfigData) - { - fontConf.SizePixels = (fontConf.SizePixels / _contentZoomFactor) * zoomFactor; - } + if (zoomFactor != _contentZoomFactor) { + for (auto& fontConf : imFonts->ConfigData) + { + fontConf.SizePixels = (fontConf.SizePixels / _contentZoomFactor) * zoomFactor; + } - // Destory font informations, let implcocos2dx recreate at newFrame - ImGui_ImplCocos2dx_DestroyDeviceObjects(); + // Destory font informations, let implcocos2dx recreate at newFrame + 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) { - auto imFonts = ImGui::GetIO().Fonts; - const ImWchar* imChars = nullptr; - switch (glyphRange) { - case CHS_GLYPH_RANGE::GENERAL: - imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon(); - break; - case CHS_GLYPH_RANGE::FULL: - imChars = imFonts->GetGlyphRangesChineseFull(); - break; - } + auto imFonts = ImGui::GetIO().Fonts; + const ImWchar* imChars = nullptr; + switch (glyphRange) { + case CHS_GLYPH_RANGE::GENERAL: + imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon(); + break; + case CHS_GLYPH_RANGE::FULL: + imChars = imFonts->GetGlyphRangesChineseFull(); + break; + } - imFonts->AddFontFromFileTTF(fontFile.c_str(), fontSize * _contentZoomFactor, nullptr, imChars); + imFonts->AddFontFromFileTTF(fontFile.c_str(), fontSize * _contentZoomFactor, nullptr, imChars); } 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() { - // create frame - ImGui_ImplCocos2dx_NewFrame(); + // create frame + ImGui_ImplCocos2dx_NewFrame(); - // draw all gui - this->update(); + // draw all gui + this->update(); - // render - ImGui::Render(); + // render + ImGui::Render(); } /* * flush ImGui draw data to engine */ void ImGuiEXT::endFrame() { - ImGui_ImplCocos2dx_RenderDrawData(ImGui::GetDrawData()); - ImGui_ImplCocos2dx_RenderPlatform(); + ImGui_ImplCocos2dx_RenderDrawData(ImGui::GetDrawData()); + ImGui_ImplCocos2dx_RenderPlatform(); } void ImGuiEXT::update() { // drived by ImGuiEXTRenderer - // clear things from last frame - usedCCRefIdMap.clear(); - usedCCRef.clear(); - // drawing commands - for (auto& pipline : _renderPiplines) - pipline.second.frame(); + // clear things from last frame + usedCCRefIdMap.clear(); + usedCCRef.clear(); + // drawing commands + for (auto& pipline : _renderPiplines) + 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 onFrame) +bool ImGuiEXT::addRenderLoop(const std::string& id, std::function func, Scene* target) { - // TODO: check whether exist - auto fourccId = fourccValue(id); - if (_renderPiplines.find(fourccId) != _renderPiplines.end()) - { - return false; - } + // TODO: check whether exist + auto fourccId = fourccValue(id); + if (_renderPiplines.find(fourccId) != _renderPiplines.end()) + { + return false; + } - auto renderer = utils::newInstance(&ImGuiEXTRenderer::initWithImGuiEXT); - scene->addChild(renderer, INT_MAX, fourccId); - _renderPiplines.emplace(fourccId, RenderPipline{ renderer, std::move(onFrame) }); + ImGuiEXTEventTracker* tracker; + if (target) + tracker = utils::newInstance(&ImGuiEXTSceneEventTracker::initWithScene, target); + else + tracker = utils::newInstance(); - return true; + if (tracker) { + _renderPiplines.emplace(fourccId, RenderPipline{ tracker, std::move(func) }); + return true; + } + return false; } void ImGuiEXT::removeRenderLoop(const std::string& id) { - auto fourccId = fourccValue(id); - const auto iter = _renderPiplines.find(fourccId); - if (iter != _renderPiplines.end()) { - auto renderer = iter->second.renderer; - if (renderer->getParent()) - renderer->removeFromParent(); - renderer->release(); - _renderPiplines.erase(iter); - } + auto fourccId = fourccValue(id); + const auto iter = _renderPiplines.find(fourccId); + if (iter != _renderPiplines.end()) { + auto tracker = iter->second.tracker; + delete tracker; + _renderPiplines.erase(iter); + } } static std::tuple getTextureUV(Sprite* sp) { - ImVec2 uv0, uv1; - if (!sp || !sp->getTexture()) - return { uv0,uv1 }; - const auto rect = sp->getTextureRect(); - const auto tex = sp->getTexture(); - const float atlasWidth = (float)tex->getPixelsWide(); - const float atlasHeight = (float)tex->getPixelsHigh(); - uv0.x = rect.origin.x / atlasWidth; - uv0.y = rect.origin.y / atlasHeight; - uv1.x = (rect.origin.x + rect.size.width) / atlasWidth; - uv1.y = (rect.origin.y + rect.size.height) / atlasHeight; - return { uv0,uv1 }; + ImVec2 uv0, uv1; + if (!sp || !sp->getTexture()) + return { uv0,uv1 }; + const auto rect = sp->getTextureRect(); + const auto tex = sp->getTexture(); + const float atlasWidth = (float)tex->getPixelsWide(); + const float atlasHeight = (float)tex->getPixelsHigh(); + uv0.x = rect.origin.x / atlasWidth; + uv0.y = rect.origin.y / atlasHeight; + uv1.x = (rect.origin.x + rect.size.width) / atlasWidth; + uv1.y = (rect.origin.y + rect.size.height) / atlasHeight; + return { uv0,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) - return; - auto size_ = size; - if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); - if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); - ImGui::PushID(getCCRefId(tex)); - ImGui::Image((ImTextureID)tex, size_, uv0, uv1, tint_col, border_col); - ImGui::PopID(); + if (!tex) + return; + auto size_ = size; + if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); + if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); + ImGui::PushID(getCCRefId(tex)); + ImGui::Image((ImTextureID)tex, size_, uv0, uv1, tint_col, border_col); + ImGui::PopID(); } void ImGuiEXT::image(Sprite* sprite, const ImVec2& size, const ImVec4& tint_col, const ImVec4& border_col) { - if (!sprite || !sprite->getTexture()) - return; - auto size_ = size; - const auto rect = sprite->getTextureRect(); - if (size_.x <= 0.f) size_.x = rect.size.width; - if (size_.y <= 0.f) size_.y = rect.size.height; - ImVec2 uv0, uv1; - std::tie(uv0, uv1) = getTextureUV(sprite); - ImGui::PushID(getCCRefId(sprite)); - ImGui::Image((ImTextureID)sprite->getTexture(), size_, uv0, uv1, tint_col, border_col); - ImGui::PopID(); + if (!sprite || !sprite->getTexture()) + return; + auto size_ = size; + const auto rect = sprite->getTextureRect(); + if (size_.x <= 0.f) size_.x = rect.size.width; + if (size_.y <= 0.f) size_.y = rect.size.height; + ImVec2 uv0, uv1; + std::tie(uv0, uv1) = getTextureUV(sprite); + ImGui::PushID(getCCRefId(sprite)); + ImGui::Image((ImTextureID)sprite->getTexture(), size_, uv0, uv1, tint_col, border_col); + ImGui::PopID(); } 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) - return false; - auto size_ = size; - if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); - if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); - ImGui::PushID(getCCRefId(tex)); - const auto ret = ImGui::ImageButton((ImTextureID)tex, - size_, uv0, uv1, frame_padding, bg_col, tint_col); - ImGui::PopID(); - return ret; + if (!tex) + return false; + auto size_ = size; + if (size_.x <= 0.f) size_.x = tex->getPixelsWide(); + if (size_.y <= 0.f) size_.y = tex->getPixelsHigh(); + ImGui::PushID(getCCRefId(tex)); + const auto ret = ImGui::ImageButton((ImTextureID)tex, + size_, uv0, uv1, frame_padding, bg_col, tint_col); + ImGui::PopID(); + return ret; } 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()) - return false; - auto size_ = size; - const auto rect = sprite->getTextureRect(); - if (size_.x <= 0.f) size_.x = rect.size.width; - if (size_.y <= 0.f) size_.y = rect.size.height; - ImVec2 uv0, uv1; - std::tie(uv0, uv1) = getTextureUV(sprite); - ImGui::PushID(getCCRefId(sprite)); - const auto ret = ImGui::ImageButton((ImTextureID)sprite->getTexture(), - size_, uv0, uv1, frame_padding, bg_col, tint_col); - ImGui::PopID(); - return ret; + if (!sprite || !sprite->getTexture()) + return false; + auto size_ = size; + const auto rect = sprite->getTextureRect(); + if (size_.x <= 0.f) size_.x = rect.size.width; + if (size_.y <= 0.f) size_.y = rect.size.height; + ImVec2 uv0, uv1; + std::tie(uv0, uv1) = getTextureUV(sprite); + ImGui::PushID(getCCRefId(sprite)); + const auto ret = ImGui::ImageButton((ImTextureID)sprite->getTexture(), + size_, uv0, uv1, frame_padding, bg_col, tint_col); + ImGui::PopID(); + return ret; } void ImGuiEXT::node(Node* node, const ImVec4& tint_col, const ImVec4& border_col) { - if (!node) - return; - const auto size = node->getContentSize(); - const auto pos = ImGui::GetCursorScreenPos(); - Mat4 tr; - tr.m[5] = -1; - tr.m[12] = pos.x; - tr.m[13] = pos.y + size.height; - if (border_col.w > 0.f) - { - tr.m[12] += 1; - tr.m[13] += 1; - } - node->setNodeToParentTransform(tr); - ImGui::PushID(getCCRefId(node)); - ImGui::Image((ImTextureID)node, - ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); - ImGui::PopID(); + if (!node) + return; + const auto size = node->getContentSize(); + const auto pos = ImGui::GetCursorScreenPos(); + Mat4 tr; + tr.m[5] = -1; + tr.m[12] = pos.x; + tr.m[13] = pos.y + size.height; + if (border_col.w > 0.f) + { + tr.m[12] += 1; + tr.m[13] += 1; + } + node->setNodeToParentTransform(tr); + ImGui::PushID(getCCRefId(node)); + ImGui::Image((ImTextureID)node, + ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col); + ImGui::PopID(); } bool ImGuiEXT::nodeButton(Node* node, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { - if (!node) - return false; - const auto size = node->getContentSize(); - const auto pos = ImGui::GetCursorScreenPos(); - Mat4 tr; - tr.m[5] = -1; - tr.m[12] = pos.x; - tr.m[13] = pos.y + size.height; - if (frame_padding >= 0) - { - tr.m[12] += (float)frame_padding; - tr.m[13] += (float)frame_padding; - } - else - { - tr.m[12] += ImGui::GetStyle().FramePadding.x; - tr.m[13] += ImGui::GetStyle().FramePadding.y; - } - node->setNodeToParentTransform(tr); - ImGui::PushID(getCCRefId(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); - ImGui::PopID(); - return ret; + if (!node) + return false; + const auto size = node->getContentSize(); + const auto pos = ImGui::GetCursorScreenPos(); + Mat4 tr; + tr.m[5] = -1; + tr.m[12] = pos.x; + tr.m[13] = pos.y + size.height; + if (frame_padding >= 0) + { + tr.m[12] += (float)frame_padding; + tr.m[13] += (float)frame_padding; + } + else + { + tr.m[12] += ImGui::GetStyle().FramePadding.x; + tr.m[13] += ImGui::GetStyle().FramePadding.y; + } + node->setNodeToParentTransform(tr); + ImGui::PushID(getCCRefId(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); + ImGui::PopID(); + return ret; } std::tuple ImGuiEXT::useTexture(Texture2D* texture) { - if (!texture) - return { nullptr,0 }; - return { (ImTextureID)texture,getCCRefId(texture) }; + if (!texture) + return { nullptr,0 }; + return { (ImTextureID)texture,getCCRefId(texture) }; } std::tuple ImGuiEXT::useSprite(Sprite* sprite) { - if (!sprite || !sprite->getTexture()) - return { nullptr,{},{},0 }; - ImVec2 uv0, uv1; - std::tie(uv0, uv1) = getTextureUV(sprite); - return { (ImTextureID)sprite->getTexture(),uv0,uv1,getCCRefId(sprite) }; + if (!sprite || !sprite->getTexture()) + return { nullptr,{},{},0 }; + ImVec2 uv0, uv1; + std::tie(uv0, uv1) = getTextureUV(sprite); + return { (ImTextureID)sprite->getTexture(),uv0,uv1,getCCRefId(sprite) }; } std::tuple ImGuiEXT::useNode(Node* node, const ImVec2& pos) { - if (!node) - return { nullptr,{},{},0 }; - const auto size = node->getContentSize(); - Mat4 tr; - tr.m[5] = -1; - tr.m[12] = pos.x; - tr.m[13] = pos.y + size.height; - node->setNodeToParentTransform(tr); - return { (ImTextureID)node,pos,ImVec2(pos.x + size.width,pos.y + size.height),getCCRefId(node) }; + if (!node) + return { nullptr,{},{},0 }; + const auto size = node->getContentSize(); + Mat4 tr; + tr.m[5] = -1; + tr.m[12] = pos.x; + tr.m[13] = pos.y + size.height; + node->setNodeToParentTransform(tr); + return { (ImTextureID)node,pos,ImVec2(pos.x + size.width,pos.y + size.height),getCCRefId(node) }; } void ImGuiEXT::setNodeColor(Node* node, const ImVec4& col) { - if (node) - { - node->setColor({ uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255) }); - node->setOpacity(uint8_t(col.w * 255)); - } + if (node) + { + node->setColor({ uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255) }); + node->setOpacity(uint8_t(col.w * 255)); + } } void ImGuiEXT::setNodeColor(Node* node, ImGuiCol col) { - if (node && 0 <= col && col < ImGuiCol_COUNT) - setNodeColor(node, ImGui::GetStyleColorVec4(col)); + if (node && 0 <= col && col < ImGuiCol_COUNT) + setNodeColor(node, ImGui::GetStyleColorVec4(col)); } void ImGuiEXT::setLabelColor(Label* label, const ImVec4& col) { - if (label) - { - label->setTextColor( - { uint8_t(col.x * 255),uint8_t(col.y * 255),uint8_t(col.z * 255),uint8_t(col.w * 255) }); - } + if (label) + { + label->setTextColor( + { 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) { - if (label) - setLabelColor(label, ImGui::GetStyleColorVec4(disabled ? ImGuiCol_TextDisabled : ImGuiCol_Text)); + if (label) + setLabelColor(label, ImGui::GetStyleColorVec4(disabled ? ImGuiCol_TextDisabled : ImGuiCol_Text)); } void ImGuiEXT::setLabelColor(Label* label, ImGuiCol col) { - if (label && 0 <= col && col < ImGuiCol_COUNT) - setLabelColor(label, ImGui::GetStyleColorVec4(col)); + if (label && 0 <= col && col < ImGuiCol_COUNT) + setLabelColor(label, ImGui::GetStyleColorVec4(col)); } ImWchar* ImGuiEXT::addGlyphRanges(const std::string& key, const std::vector& ranges) { - auto it = glyphRanges.find(key); - // the pointer must be persistant, do not replace - if (it != glyphRanges.end()) - return it->second.data(); - glyphRanges[key] = ranges; - if (ranges.empty()) - glyphRanges[key].push_back(0); - return glyphRanges[key].data(); + auto it = glyphRanges.find(key); + // the pointer must be persistant, do not replace + if (it != glyphRanges.end()) + return it->second.data(); + glyphRanges[key] = ranges; + if (ranges.empty()) + glyphRanges[key].push_back(0); + return glyphRanges[key].data(); } void ImGuiEXT::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end) { - if (!dst || !src || start > end) - return; - for (auto i = start; i <= end; ++i) - { - const auto g = src->FindGlyphNoFallback(i); - if (g) - { - // TODO - // dst->AddGlyph(g->Codepoint, g->X0, g->Y0, g->X1, g->Y1, g->U0, g->V0, g->U1, g->V1, g->AdvanceX); - } - } - dst->BuildLookupTable(); + if (!dst || !src || start > end) + return; + for (auto i = start; i <= end; ++i) + { + const auto g = src->FindGlyphNoFallback(i); + if (g) + { + // TODO + // dst->AddGlyph(g->Codepoint, g->X0, g->Y0, g->X1, g->Y1, g->U0, g->V0, g->U1, g->V1, g->AdvanceX); + } + } + dst->BuildLookupTable(); } int ImGuiEXT::getCCRefId(Ref* p) { - int id = 0; - const auto it = usedCCRefIdMap.find(p); - if (it == usedCCRefIdMap.end()) - { - usedCCRefIdMap[p] = 0; - usedCCRef.pushBack(p); - } - else - id = ++it->second; - // BKDR hash - constexpr unsigned int seed = 131; - unsigned int hash = 0; - for (auto i = 0u; i < sizeof(void*); ++i) - hash = hash * seed + ((const char*)&p)[i]; - for (auto i = 0u; i < sizeof(int); ++i) - hash = hash * seed + ((const char*)&id)[i]; - return (int)hash; + int id = 0; + const auto it = usedCCRefIdMap.find(p); + if (it == usedCCRefIdMap.end()) + { + usedCCRefIdMap[p] = 0; + usedCCRef.pushBack(p); + } + else + id = ++it->second; + // BKDR hash + constexpr unsigned int seed = 131; + unsigned int hash = 0; + for (auto i = 0u; i < sizeof(void*); ++i) + hash = hash * seed + ((const char*)&p)[i]; + for (auto i = 0u; i < sizeof(int); ++i) + hash = hash * seed + ((const char*)&id)[i]; + return (int)hash; } #if defined(HAVE_IMGUI_MARKDOWN) @@ -473,64 +536,64 @@ static ImGui::MarkdownImageData ImGuiMarkdownInvalidImageData = { false, false, void MarkdownLinkCallback(ImGui::MarkdownLinkCallbackData data) { - if (ImGuiMarkdownLinkCallback) - { - ImGuiMarkdownLinkCallback( - { data.text, (size_t)data.textLength }, { data.link, (size_t)data.linkLength }, data.isImage); - } + if (ImGuiMarkdownLinkCallback) + { + ImGuiMarkdownLinkCallback( + { data.text, (size_t)data.textLength }, { data.link, (size_t)data.linkLength }, data.isImage); + } } ImGui::MarkdownImageData MarkdownImageCallback(ImGui::MarkdownLinkCallbackData data) { - if (!data.isImage || !ImGuiMarkdownImageCallback) - return ImGuiMarkdownInvalidImageData; - Sprite* sp; ImVec2 size; ImVec4 tint_col; ImVec4 border_col; - std::tie(sp, size, tint_col, border_col) = ImGuiMarkdownImageCallback( - { data.text, (size_t)data.textLength }, - { data.link, (size_t)data.linkLength }); - if(!sp || !sp->getTexture()) - return ImGuiMarkdownInvalidImageData; - auto size_ = size; - const auto rect = sp->getTextureRect(); - if (size_.x <= 0.f) size_.x = rect.size.width; - if (size_.y <= 0.f) size_.y = rect.size.height; - ImVec2 uv0, uv1; - std::tie(uv0, uv1) = getTextureUV(sp); - ImGuiEXT::getInstance()->getCCRefId(sp); - return { true, true, (ImTextureID)sp->getTexture(), size_,uv0, uv1, tint_col, border_col }; + if (!data.isImage || !ImGuiMarkdownImageCallback) + return ImGuiMarkdownInvalidImageData; + Sprite* sp; ImVec2 size; ImVec4 tint_col; ImVec4 border_col; + std::tie(sp, size, tint_col, border_col) = ImGuiMarkdownImageCallback( + { data.text, (size_t)data.textLength }, + { data.link, (size_t)data.linkLength }); + if (!sp || !sp->getTexture()) + return ImGuiMarkdownInvalidImageData; + auto size_ = size; + const auto rect = sp->getTextureRect(); + if (size_.x <= 0.f) size_.x = rect.size.width; + if (size_.y <= 0.f) size_.y = rect.size.height; + ImVec2 uv0, uv1; + std::tie(uv0, uv1) = getTextureUV(sp); + ImGuiEXT::getInstance()->getCCRefId(sp); + return { true, true, (ImTextureID)sp->getTexture(), size_,uv0, uv1, tint_col, border_col }; } static std::string ImGuiMarkdownLinkIcon; static ImGui::MarkdownConfig ImGuiMarkdownConfig = { - MarkdownLinkCallback, MarkdownImageCallback, "" }; + MarkdownLinkCallback, MarkdownImageCallback, "" }; void ImGuiEXT::setMarkdownLinkCallback(const MdLinkCallback& f) { - ImGuiMarkdownLinkCallback = f; + ImGuiMarkdownLinkCallback = f; } void ImGuiEXT::setMarkdownImageCallback(const MdImageCallback& f) { - ImGuiMarkdownImageCallback = f; + ImGuiMarkdownImageCallback = f; } void ImGuiEXT::setMarkdownFont(int index, ImFont* font, bool seperator, float scale) { - if (index < 0 || index >= ImGui::MarkdownConfig::NUMHEADINGS) - return; - ImGuiMarkdownConfig.headingFormats[index] = { font,seperator }; - ImGuiMarkdownConfig.headingScales[index] = scale; + if (index < 0 || index >= ImGui::MarkdownConfig::NUMHEADINGS) + return; + ImGuiMarkdownConfig.headingFormats[index] = { font,seperator }; + ImGuiMarkdownConfig.headingScales[index] = scale; } void ImGuiEXT::setMarkdownLinkIcon(const std::string& icon) { - ImGuiMarkdownLinkIcon = icon; - ImGuiMarkdownConfig.linkIcon = ImGuiMarkdownLinkIcon.c_str(); + ImGuiMarkdownLinkIcon = icon; + ImGuiMarkdownConfig.linkIcon = ImGuiMarkdownLinkIcon.c_str(); } void ImGuiEXT::markdown(const std::string& content) { - ImGui::Markdown(content.c_str(), content.size(), ImGuiMarkdownConfig); + ImGui::Markdown(content.c_str(), content.size(), ImGuiMarkdownConfig); } #endif diff --git a/extensions/ImGuiEXT/CCImGuiEXT.h b/extensions/ImGuiEXT/CCImGuiEXT.h index c083feec5d..d8444ec5f4 100644 --- a/extensions/ImGuiEXT/CCImGuiEXT.h +++ b/extensions/ImGuiEXT/CCImGuiEXT.h @@ -10,145 +10,145 @@ NS_CC_EXT_BEGIN -class ImGuiEXTRenderer; +class ImGuiEXTEventTracker; class ImGuiEXT { - friend class ImGuiEXTRenderer; - void init(); + friend class ImGuiEXTRenderer; + void init(); public: - enum class CHS_GLYPH_RANGE { - NONE, - GENERAL, - FULL - }; + enum class CHS_GLYPH_RANGE { + NONE, + GENERAL, + FULL + }; - enum { - DEFAULT_FONT_SIZE = 13 // see imgui.cpp - }; + enum { + DEFAULT_FONT_SIZE = 13 // see imgui.cpp + }; - static ImGuiEXT* getInstance(); - static void destroyInstance(); - static void setOnInit(const std::function& callBack); + static ImGuiEXT* getInstance(); + static void destroyInstance(); + static void setOnInit(const std::function& callBack); - /// - /// Scale ImGui with majorMoniter DPI scaling - /// - /// Usually is 1.0 - /// The full path of .ttc/.ttf file - /// The final contentZoomFactor = userScale * dpiScale - float scaleAllByDPI(float userScale); - float getContentZoomFactor() const { return _contentZoomFactor; } + /// + /// Scale ImGui with majorMoniter DPI scaling + /// + /// Usually is 1.0 + /// The full path of .ttc/.ttf file + /// The final contentZoomFactor = userScale * dpiScale + float scaleAllByDPI(float userScale); + float getContentZoomFactor() const { return _contentZoomFactor; } - /// - /// Add ImGui font with contentZoomFactor - /// - /// - /// - void addFont(const std::string& fontFile, float fontSize = DEFAULT_FONT_SIZE, CHS_GLYPH_RANGE glyphRange = CHS_GLYPH_RANGE::NONE); - void clearFonts(); + /// + /// Add ImGui font with contentZoomFactor + /// + /// + /// + void addFont(const std::string& fontFile, float fontSize = DEFAULT_FONT_SIZE, CHS_GLYPH_RANGE glyphRange = CHS_GLYPH_RANGE::NONE); + void clearFonts(); - /// - /// Add a ImGui render loop to specific scene - /// - /// The FOURCC id of render loop, starts with '#', such as "#abcd" - /// the target scene to render ImGui - /// the ImGui render loop - bool addRenderLoop(const std::string& id, Scene* target, std::function func); + /// + /// Add a ImGui render loop to specific scene + /// + /// The FOURCC id of render loop, starts with '#', such as "#abcd" + /// the ImGui render loop + /// The target scene to track event, nullptr for global, useful for global GM tools + bool addRenderLoop(const std::string& id, std::function func, Scene* target); - /// - /// Remove ImGui render loop - /// - /// FOURCC starts with '#', such as "#abcd" - void removeRenderLoop(const std::string& id); + /// + /// Remove ImGui render loop + /// + /// FOURCC starts with '#', such as "#abcd" + void removeRenderLoop(const std::string& id); - // imgui helper - void image( - Texture2D* tex, - const ImVec2& size, - const ImVec2& uv0 = ImVec2(0, 0), - const ImVec2& uv1 = ImVec2(1, 1), - const ImVec4& tint_col = ImVec4(1, 1, 1, 1), - const ImVec4& border_col = ImVec4(0, 0, 0, 0)); - void image( - Sprite* sprite, - const ImVec2& size, - const ImVec4& tint_col = ImVec4(1, 1, 1, 1), - const ImVec4& border_col = ImVec4(0, 0, 0, 0)); - bool imageButton( - Texture2D* tex, - const ImVec2& size, - const ImVec2& uv0 = ImVec2(0, 0), - const ImVec2& uv1 = ImVec2(1, 1), - int frame_padding = -1, - const ImVec4& bg_col = ImVec4(0, 0, 0, 0), - const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); - bool imageButton( - Sprite* sprite, - const ImVec2& size, - int frame_padding = -1, - const ImVec4& bg_col = ImVec4(0, 0, 0, 0), - const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + // imgui helper + void image( + Texture2D* tex, + const ImVec2& size, + const ImVec2& uv0 = ImVec2(0, 0), + const ImVec2& uv1 = ImVec2(1, 1), + const ImVec4& tint_col = ImVec4(1, 1, 1, 1), + const ImVec4& border_col = ImVec4(0, 0, 0, 0)); + void image( + Sprite* sprite, + const ImVec2& size, + const ImVec4& tint_col = ImVec4(1, 1, 1, 1), + const ImVec4& border_col = ImVec4(0, 0, 0, 0)); + bool imageButton( + Texture2D* tex, + const ImVec2& size, + const ImVec2& uv0 = ImVec2(0, 0), + const ImVec2& uv1 = ImVec2(1, 1), + int frame_padding = -1, + const ImVec4& bg_col = ImVec4(0, 0, 0, 0), + const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + bool imageButton( + Sprite* sprite, + const ImVec2& size, + int frame_padding = -1, + const ImVec4& bg_col = ImVec4(0, 0, 0, 0), + const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); - void node( - Node* node, - const ImVec4& tint_col = ImVec4(1, 1, 1, 1), - const ImVec4& border_col = ImVec4(0, 0, 0, 0)); - bool nodeButton( - Node* node, - int frame_padding = -1, - const ImVec4& bg_col = ImVec4(0, 0, 0, 0), - const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + void node( + Node* node, + const ImVec4& tint_col = ImVec4(1, 1, 1, 1), + const ImVec4& border_col = ImVec4(0, 0, 0, 0)); + bool nodeButton( + Node* node, + int frame_padding = -1, + const ImVec4& bg_col = ImVec4(0, 0, 0, 0), + const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); - std::tuple useTexture(Texture2D* texture); - std::tuple useSprite(Sprite* sprite); - std::tuple useNode(Node* node, const ImVec2& pos); + std::tuple useTexture(Texture2D* texture); + std::tuple useSprite(Sprite* sprite); + std::tuple useNode(Node* node, const ImVec2& pos); - static void setNodeColor(Node* node, const ImVec4& col); - static void setNodeColor(Node* node, ImGuiCol col); - static void setLabelColor(Label* label, const ImVec4& col); - static void setLabelColor(Label* label, bool disabled = false); - static void setLabelColor(Label* label, ImGuiCol col); + static void setNodeColor(Node* node, const ImVec4& col); + static void setNodeColor(Node* node, ImGuiCol col); + static void setLabelColor(Label* label, const ImVec4& col); + static void setLabelColor(Label* label, bool disabled = false); + static void setLabelColor(Label* label, ImGuiCol col); - ImWchar* addGlyphRanges(const std::string& key, const std::vector& ranges); - static void mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end); - int getCCRefId(Ref* p); + ImWchar* addGlyphRanges(const std::string& key, const std::vector& ranges); + static void mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end); + int getCCRefId(Ref* p); #if defined(HAVE_IMGUI_MARKDOWN) - // markdown + // markdown - using MdLinkCallback = std::function; - using MdImageCallback = std::function(const std::string&, const std::string&)>; + using MdLinkCallback = std::function; + using MdImageCallback = std::function(const std::string&, const std::string&)>; - void setMarkdownLinkCallback(const MdLinkCallback& f); - void setMarkdownImageCallback(const MdImageCallback& f); - void setMarkdownFont(int index, ImFont* font, bool seperator, float scale = 1.f); - void setMarkdownLinkIcon(const std::string& icon); - void markdown(const std::string& content); + void setMarkdownLinkCallback(const MdLinkCallback& f); + void setMarkdownImageCallback(const MdImageCallback& f); + void setMarkdownFont(int index, ImFont* font, bool seperator, float scale = 1.f); + void setMarkdownLinkIcon(const std::string& icon); + void markdown(const std::string& content); #endif private: - // perform draw ImGui stubs - void beginFrame(); - void update(); - void endFrame(); + // perform draw ImGui stubs + void beginFrame(); + void update(); + void endFrame(); private: - static std::function _onInit; - - struct RenderPipline { - ImGuiEXTRenderer* renderer; - std::function frame; - }; + static std::function _onInit; - std::unordered_map _renderPiplines; + struct RenderPipline { + ImGuiEXTEventTracker* tracker; + std::function frame; + }; - std::unordered_map usedCCRefIdMap; - // cocos objects should be retained until next frame - Vector usedCCRef; - std::unordered_map> glyphRanges; + std::unordered_map _renderPiplines; - float _contentZoomFactor = 1.0f; + std::unordered_map usedCCRefIdMap; + // cocos objects should be retained until next frame + Vector usedCCRef; + std::unordered_map> glyphRanges; + + float _contentZoomFactor = 1.0f; }; NS_CC_EXT_END