axmol/extensions/ImGui/ImGuiPresenter.cpp

733 lines
22 KiB
C++
Raw Normal View History

#include "ImGuiPresenter.h"
#include <assert.h>
#if (AX_TARGET_PLATFORM == AX_PLATFORM_ANDROID)
2023-09-12 19:30:15 +08:00
# include "imgui_impl_ax_android.h"
#else
2023-09-12 19:30:15 +08:00
# include "imgui_impl_ax.h"
#endif
#include "imgui_internal.h"
2020-09-04 17:19:51 +08:00
2022-02-08 12:43:16 +08:00
// TODO: mac metal
2023-09-03 13:22:40 +08:00
#if defined(AX_USE_GL) && defined(AX_PLATFORM_PC)
2022-07-16 10:43:05 +08:00
# define AX_IMGUI_ENABLE_MULTI_VIEWPORT 1
2022-02-08 12:43:16 +08:00
#else
2022-07-16 10:43:05 +08:00
# define AX_IMGUI_ENABLE_MULTI_VIEWPORT 0
2022-02-08 12:43:16 +08:00
#endif
NS_AX_EXT_BEGIN
2020-09-04 17:19:51 +08:00
static uint32_t fourccValue(std::string_view str)
2021-12-25 10:04:45 +08:00
{
if (str.empty() || str[0] != '#')
return (uint32_t)-1;
uint32_t value = 0;
memcpy(&value, str.data() + 1, std::min(sizeof(value), str.size() - 1));
return value;
}
class ImGuiEventTracker
2021-12-25 10:04:45 +08:00
{
public:
virtual ~ImGuiEventTracker() {}
};
// Track scene event and check whether routed to the scene graph
class ImGuiSceneEventTracker : public ImGuiEventTracker
{
public:
bool initWithScene(Scene* scene)
{
2022-07-16 10:43:05 +08:00
#ifdef AX_PLATFORM_PC
_trackLayer = utils::newInstance<Node>(&Node::initLayer);
// note: when at the first click to focus the window, this will not take effect
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
2021-12-25 10:04:45 +08:00
listener->onTouchBegan = [this](Touch* touch, Event*) -> bool { return ImGui::GetIO().WantCaptureMouse; };
_trackLayer->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, _trackLayer);
// add by halx99
auto stopAnyMouse = [=](EventMouse* event) {
2021-12-25 10:04:45 +08:00
if (ImGui::GetIO().WantCaptureMouse)
{
event->stopPropagation();
}
};
2021-12-25 10:04:45 +08:00
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);
/*
2021-12-25 10:04:45 +08:00
* 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;
}
~ImGuiSceneEventTracker()
{
2022-07-16 10:43:05 +08:00
#ifdef AX_PLATFORM_PC
2021-12-25 10:04:45 +08:00
if (_trackLayer)
{
if (_trackLayer->getParent())
_trackLayer->removeFromParent();
_trackLayer->release();
}
#endif
}
private:
Node* _trackLayer = nullptr;
};
class ImGuiGlobalEventTracker : public ImGuiEventTracker
{
static const int highestPriority = (std::numeric_limits<int>::min)();
2021-12-25 10:04:45 +08:00
public:
bool init()
{
2022-07-16 10:43:05 +08:00
#ifdef AX_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);
2021-12-25 10:04:45 +08:00
_touchListener->onTouchBegan = [this](Touch* touch, Event*) -> bool { return ImGui::GetIO().WantCaptureMouse; };
eventDispatcher->addEventListenerWithFixedPriority(_touchListener, highestPriority);
// add by halx99
auto stopAnyMouse = [=](EventMouse* event) {
2021-12-25 10:04:45 +08:00
if (ImGui::GetIO().WantCaptureMouse)
{
event->stopPropagation();
}
};
2021-12-25 10:04:45 +08:00
_mouseListener = utils::newInstance<EventListenerMouse>();
_mouseListener->onMouseDown = _mouseListener->onMouseUp = stopAnyMouse;
eventDispatcher->addEventListenerWithFixedPriority(_mouseListener, highestPriority);
#endif
return true;
}
~ImGuiGlobalEventTracker()
2021-12-25 10:04:45 +08:00
{
2022-07-16 10:43:05 +08:00
#ifdef AX_PLATFORM_PC
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeEventListener(_mouseListener);
eventDispatcher->removeEventListener(_touchListener);
_mouseListener->release();
_touchListener->release();
#endif
}
EventListenerTouchOneByOne* _touchListener = nullptr;
2021-12-25 10:04:45 +08:00
EventListenerMouse* _mouseListener = nullptr;
};
static ImGuiPresenter* _instance = nullptr;
std::function<void(ImGuiPresenter*)> ImGuiPresenter::_onInit;
2020-09-04 17:19:51 +08:00
ImGuiPresenter* ImGuiPresenter::getInstance()
2020-09-04 17:19:51 +08:00
{
if (_instance == nullptr)
{
_instance = new ImGuiPresenter();
_instance->init();
if (_onInit)
_onInit(_instance);
}
return _instance;
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::destroyInstance()
2020-09-04 17:19:51 +08:00
{
if (_instance)
{
_instance->cleanup();
delete _instance;
_instance = nullptr;
}
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::init()
{
2022-02-08 12:43:16 +08:00
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
(void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
2022-07-16 10:43:05 +08:00
#if AX_IMGUI_ENABLE_MULTI_VIEWPORT
2022-02-08 12:43:16 +08:00
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
#endif
// io.ConfigViewportsNoAutoMerge = true;
// io.ConfigViewportsNoTaskBarIcon = true;
// io.ConfigViewportsNoDefaultParent = true;
// io.ConfigDockingAlwaysTabBar = true;
// io.ConfigDockingTransparentPayload = true;
// io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: Experimental. THIS CURRENTLY DOESN'T
// WORK AS EXPECTED. DON'T USE IN USER APP! io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; //
// FIXME-DPI: Experimental.
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// ImGui::StyleColorsClassic();
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular
// ones.
ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
#if (AX_TARGET_PLATFORM == AX_PLATFORM_ANDROID)
ImGui_ImplAndroid_InitForAx(Director::getInstance()->getOpenGLView(), true);
#else
2022-02-08 12:43:16 +08:00
auto window = static_cast<GLViewImpl*>(Director::getInstance()->getOpenGLView())->getWindow();
2022-10-01 16:24:52 +08:00
ImGui_ImplGlfw_InitForAx(window, true);
#endif
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_Init();
2022-02-08 12:43:16 +08:00
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_SetCustomFontLoader(&ImGuiPresenter::loadCustomFonts, this);
ImGui::StyleColorsClassic();
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->addCustomEventListener(Director::EVENT_BEFORE_DRAW, [this](EventCustom*) { beginFrame(); });
eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_VISIT, [this](EventCustom*) { endFrame(); });
}
void ImGuiPresenter::cleanup()
{
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT);
eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW);
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_SetCustomFontLoader(nullptr, nullptr);
ImGui_ImplAx_Shutdown();
#if (AX_TARGET_PLATFORM == AX_PLATFORM_ANDROID)
ImGui_ImplAndroid_Shutdown();
#else
2022-02-08 12:43:16 +08:00
ImGui_ImplGlfw_Shutdown();
#endif
2022-07-16 10:43:05 +08:00
AX_SAFE_RELEASE_NULL(_fontsTexture);
2022-02-08 12:43:16 +08:00
ImGui::DestroyContext();
2023-09-12 19:30:15 +08:00
if (!_renderLoops.empty())
{
for (auto item : _renderLoops)
{
delete item.second.tracker;
}
_renderLoops.clear();
}
}
void ImGuiPresenter::setOnInit(const std::function<void(ImGuiPresenter*)>& callBack)
2020-09-04 17:19:51 +08:00
{
_onInit = callBack;
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::loadCustomFonts(void* ud)
{
auto thiz = (ImGuiPresenter*)ud;
auto imFonts = ImGui::GetIO().Fonts;
imFonts->Clear();
auto contentZoomFactor = thiz->_contentZoomFactor;
2021-12-25 10:04:45 +08:00
for (auto& fontInfo : thiz->_fontsInfoMap)
{
const ImWchar* imChars = nullptr;
2021-12-25 10:04:45 +08:00
switch (fontInfo.second.glyphRange)
{
case CHS_GLYPH_RANGE::GENERAL:
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
break;
case CHS_GLYPH_RANGE::FULL:
imChars = imFonts->GetGlyphRangesChineseFull();
break;
default:;
}
auto fontData = FileUtils::getInstance()->getDataFromFile(fontInfo.first);
2022-07-16 10:43:05 +08:00
AXASSERT(!fontData.isNull(), "Cannot load font for IMGUI");
ssize_t bufferSize = 0;
2021-12-25 10:04:45 +08:00
auto* buffer = fontData.takeBuffer(&bufferSize); // Buffer automatically freed by IMGUI
2021-12-25 10:04:45 +08:00
imFonts->AddFontFromMemoryTTF(buffer, bufferSize, fontInfo.second.fontSize * contentZoomFactor, nullptr,
imChars);
}
}
float ImGuiPresenter::enableDPIScale(float userScale)
2020-09-07 21:22:03 +08:00
{
float xscale = 1.0f;
#if (AX_TARGET_PLATFORM != AX_PLATFORM_ANDROID)
// Gets scale
glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, nullptr);
2023-09-12 19:30:15 +08:00
#else
// refer to: https://developer.android.com/training/multiscreen/screendensities?hl=en-us
xscale = Device::getDPI() / 160.0f;
#endif
auto zoomFactor = userScale * xscale;
2020-09-07 21:22:03 +08:00
auto imFonts = ImGui::GetIO().Fonts;
2020-09-07 21:22:03 +08:00
// clear before add new font
2021-12-25 10:04:45 +08:00
auto fontConf = imFonts->ConfigData; // copy font config data
2020-09-07 21:22:03 +08:00
2021-12-25 10:04:45 +08:00
if (zoomFactor != _contentZoomFactor)
{
for (auto& fontConf : imFonts->ConfigData)
{
fontConf.SizePixels = (fontConf.SizePixels / _contentZoomFactor) * zoomFactor;
}
2020-09-07 21:22:03 +08:00
// Destory font informations, let implcocos2dx recreate at newFrame
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_SetDeviceObjectsDirty();
2020-09-07 21:22:03 +08:00
ImGui::GetStyle().ScaleAllSizes(zoomFactor);
2020-09-07 21:22:03 +08:00
_contentZoomFactor = zoomFactor;
}
2020-09-07 21:22:03 +08:00
return zoomFactor;
2020-09-07 21:22:03 +08:00
}
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)
2020-09-07 21:22:03 +08:00
{
2021-12-25 10:04:45 +08:00
if (FileUtils::getInstance()->isFileExistInternal(fontFile))
{
if (_fontsInfoMap.emplace(fontFile, FontInfo{fontSize, glyphRange}).second)
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_SetDeviceObjectsDirty();
}
}
void ImGuiPresenter::removeFont(std::string_view fontFile)
{
auto count = _fontsInfoMap.size();
_fontsInfoMap.erase(fontFile);
2021-12-25 10:04:45 +08:00
if (count != _fontsInfoMap.size())
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_SetDeviceObjectsDirty();
2020-09-07 21:22:03 +08:00
}
void ImGuiPresenter::clearFonts()
2020-09-07 21:22:03 +08:00
{
bool haveCustomFonts = !_fontsInfoMap.empty();
_fontsInfoMap.clear();
2021-12-25 10:04:45 +08:00
if (haveCustomFonts)
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_SetDeviceObjectsDirty();
// auto drawData = ImGui::GetDrawData();
// if(drawData) drawData->Clear();
2020-09-07 21:22:03 +08:00
}
void ImGuiPresenter::end()
2020-09-10 17:53:17 +08:00
{
_purgeNextLoop = true;
}
/*
2021-12-25 10:04:45 +08:00
* begin ImGui frame and draw ImGui stubs
*/
void ImGuiPresenter::beginFrame()
2021-12-25 10:04:45 +08:00
{ // drived by event Director::EVENT_BEFORE_DRAW from engine mainLoop
if (_purgeNextLoop)
2020-09-10 17:53:17 +08:00
{
Director::getInstance()->end();
return;
}
if (!_renderLoops.empty())
2021-12-25 10:04:45 +08:00
{
// create frame
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_NewFrame();
#if (AX_TARGET_PLATFORM == AX_PLATFORM_ANDROID)
ImGui_ImplAndroid_NewFrame();
#else
2022-02-08 12:43:16 +08:00
ImGui_ImplGlfw_NewFrame();
#endif
2022-02-08 12:43:16 +08:00
ImGui::NewFrame();
// move to endFrame?
2022-09-26 22:56:47 +08:00
_fontsTexture = (Texture2D*)ImGui_ImplAx_GetFontsTexture();
assert(_fontsTexture != nullptr);
_fontsTexture->retain();
// draw all gui
this->update();
++_beginFrames;
}
}
/*
2021-12-25 10:04:45 +08:00
* flush ImGui draw data to engine
*/
void ImGuiPresenter::endFrame()
2021-12-25 10:04:45 +08:00
{
if (_beginFrames > 0)
{
// render
ImGui::Render();
auto drawData = ImGui::GetDrawData();
if (drawData)
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_RenderDrawData(drawData);
2022-09-26 22:56:47 +08:00
ImGui_ImplAx_RenderPlatform();
--_beginFrames;
2022-07-16 10:43:05 +08:00
AX_SAFE_RELEASE_NULL(_fontsTexture);
}
}
void ImGuiPresenter::update()
2020-09-08 16:15:40 +08:00
{
// clear things from last frame
usedCCRefIdMap.clear();
usedCCRef.clear();
// drawing commands
2023-09-12 19:30:15 +08:00
for (auto iter = _renderLoops.begin(); iter != _renderLoops.end();)
{
auto& imLoop = iter->second;
2023-09-12 19:30:15 +08:00
if (imLoop.removing)
{
auto tracker = imLoop.tracker;
iter = _renderLoops.erase(iter);
delete tracker;
continue;
}
2023-09-12 19:30:15 +08:00
imLoop.func(); // invoke ImGui loop func
++iter;
}
// commands will be processed after update
2020-09-04 17:19:51 +08:00
}
bool ImGuiPresenter::addRenderLoop(std::string_view id, std::function<void()> func, Scene* target)
2020-09-04 17:19:51 +08:00
{
2023-09-12 19:30:15 +08:00
auto tracker = target ? static_cast<ImGuiEventTracker*>(utils::newInstance<ImGuiSceneEventTracker>(
&ImGuiSceneEventTracker::initWithScene, target))
: static_cast<ImGuiEventTracker*>(utils::newInstance<ImGuiGlobalEventTracker>());
2023-09-12 19:30:15 +08:00
auto fourccId = fourccValue(id);
auto iter = _renderLoops.find(fourccId);
if (iter == _renderLoops.end())
2021-12-25 10:04:45 +08:00
{
_renderLoops.emplace(fourccId, ImGuiLoop{tracker, std::move(func)});
return true;
}
2023-09-12 19:30:15 +08:00
// allow reuse imLoop, update func, tracker, removing status
auto& imLoop = iter->second;
imLoop.func = std::move(func);
imLoop.tracker = tracker;
if (imLoop.removing)
imLoop.removing = false;
return true;
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::removeRenderLoop(std::string_view id)
2020-09-04 17:19:51 +08:00
{
2021-12-25 10:04:45 +08:00
auto fourccId = fourccValue(id);
const auto iter = _renderLoops.find(fourccId);
if (iter != _renderLoops.end())
iter->second.removing = true;
2020-09-04 17:19:51 +08:00
}
static std::tuple<ImVec2, ImVec2> getTextureUV(Sprite* sp)
{
ImVec2 uv0, uv1;
if (!sp || !sp->getTexture())
2021-12-25 10:04:45 +08:00
return std::tuple<ImVec2, ImVec2>{uv0, uv1};
const auto& rect = sp->getTextureRect();
const auto tex = sp->getTexture();
const float atlasWidth = (float)tex->getPixelsWide();
const float atlasHeight = (float)tex->getPixelsHigh();
2021-12-25 10:04:45 +08:00
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 std::tuple<ImVec2, ImVec2>{uv0, uv1};
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::image(Texture2D* tex,
2023-09-12 19:30:15 +08:00
const ImVec2& size,
const ImVec2& uv0,
const ImVec2& uv1,
const ImVec4& tint_col,
const ImVec4& border_col)
2020-09-04 17:19:51 +08:00
{
if (!tex)
return;
auto size_ = size;
2021-12-25 10:04:45 +08:00
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();
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::image(Sprite* sprite, const ImVec2& size, const ImVec4& tint_col, const ImVec4& border_col)
2020-09-04 17:19:51 +08:00
{
if (!sprite || !sprite->getTexture())
return;
2021-12-25 10:04:45 +08:00
auto size_ = size;
2020-09-08 16:15:40 +08:00
const auto& rect = sprite->getTextureRect();
2021-12-25 10:04:45 +08:00
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();
2020-09-04 17:19:51 +08:00
}
bool ImGuiPresenter::imageButton(Texture2D* tex,
2023-09-12 19:30:15 +08:00
const ImVec2& size,
const ImVec2& uv0,
const ImVec2& uv1,
int frame_padding,
const ImVec4& bg_col,
const ImVec4& tint_col)
2020-09-04 17:19:51 +08:00
{
if (!tex)
return false;
auto size_ = size;
2021-12-25 10:04:45 +08:00
if (size_.x <= 0.f)
size_.x = tex->getPixelsWide();
if (size_.y <= 0.f)
size_.y = tex->getPixelsHigh();
ImGui::PushID(getCCRefId(tex));
2021-12-25 10:04:45 +08:00
const auto ret = ImGui::ImageButton((ImTextureID)tex, size_, uv0, uv1, frame_padding, bg_col, tint_col);
ImGui::PopID();
return ret;
2020-09-04 17:19:51 +08:00
}
bool ImGuiPresenter::imageButton(Sprite* sprite,
2023-09-12 19:30:15 +08:00
const ImVec2& size,
int frame_padding,
const ImVec4& bg_col,
const ImVec4& tint_col)
{
if (!sprite || !sprite->getTexture())
return false;
2021-12-25 10:04:45 +08:00
auto size_ = size;
2020-09-08 16:15:40 +08:00
const auto& rect = sprite->getTextureRect();
2021-12-25 10:04:45 +08:00
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));
2021-12-25 10:04:45 +08:00
const auto ret =
ImGui::ImageButton((ImTextureID)sprite->getTexture(), size_, uv0, uv1, frame_padding, bg_col, tint_col);
ImGui::PopID();
return ret;
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::node(Node* node, const ImVec4& tint_col, const ImVec4& border_col)
2020-09-04 17:19:51 +08:00
{
if (!node)
return;
const auto size = node->getContentSize();
2021-12-25 10:04:45 +08:00
const auto pos = ImGui::GetCursorScreenPos();
Mat4 tr;
2021-12-25 10:04:45 +08:00
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));
2021-12-25 10:04:45 +08:00
ImGui::Image((ImTextureID)node, ImVec2(size.width, size.height), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col);
ImGui::PopID();
2020-09-04 17:19:51 +08:00
}
bool ImGuiPresenter::nodeButton(Node* node, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
2020-09-04 17:19:51 +08:00
{
if (!node)
return false;
const auto size = node->getContentSize();
2021-12-25 10:04:45 +08:00
const auto pos = ImGui::GetCursorScreenPos();
Mat4 tr;
2021-12-25 10:04:45 +08:00
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));
2021-12-25 10:04:45 +08:00
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;
2020-09-04 17:19:51 +08:00
}
std::tuple<ImTextureID, int> ImGuiPresenter::useTexture(Texture2D* texture)
2020-09-04 17:19:51 +08:00
{
if (!texture)
2021-12-25 10:04:45 +08:00
return std::tuple<ImTextureID, int>{nullptr, 0};
return std::tuple<ImTextureID, int>{(ImTextureID)texture, getCCRefId(texture)};
2020-09-04 17:19:51 +08:00
}
std::tuple<ImTextureID, ImVec2, ImVec2, int> ImGuiPresenter::useSprite(Sprite* sprite)
2020-09-04 17:19:51 +08:00
{
if (!sprite || !sprite->getTexture())
2021-12-25 10:04:45 +08:00
return std::tuple<ImTextureID, ImVec2, ImVec2, int>{nullptr, {}, {}, 0};
ImVec2 uv0, uv1;
std::tie(uv0, uv1) = getTextureUV(sprite);
2021-12-25 10:04:45 +08:00
return std::tuple<ImTextureID, ImVec2, ImVec2, int>{(ImTextureID)sprite->getTexture(), uv0, uv1,
getCCRefId(sprite)};
2020-09-04 17:19:51 +08:00
}
std::tuple<ImTextureID, ImVec2, ImVec2, int> ImGuiPresenter::useNode(Node* node, const ImVec2& pos)
2020-09-04 17:19:51 +08:00
{
if (!node)
2021-12-25 10:04:45 +08:00
return std::tuple<ImTextureID, ImVec2, ImVec2, int>{nullptr, {}, {}, 0};
const auto size = node->getContentSize();
Mat4 tr;
2021-12-25 10:04:45 +08:00
tr.m[5] = -1;
tr.m[12] = pos.x;
tr.m[13] = pos.y + size.height;
node->setNodeToParentTransform(tr);
2021-12-25 10:04:45 +08:00
return std::tuple<ImTextureID, ImVec2, ImVec2, int>{
(ImTextureID)node, pos, ImVec2(pos.x + size.width, pos.y + size.height), getCCRefId(node)};
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::setNodeColor(Node* node, const ImVec4& col)
2020-09-04 17:19:51 +08:00
{
if (node)
{
2021-12-25 10:04:45 +08:00
node->setColor({uint8_t(col.x * 255), uint8_t(col.y * 255), uint8_t(col.z * 255)});
node->setOpacity(uint8_t(col.w * 255));
}
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::setNodeColor(Node* node, ImGuiCol col)
2020-09-04 17:19:51 +08:00
{
if (node && 0 <= col && col < ImGuiCol_COUNT)
setNodeColor(node, ImGui::GetStyleColorVec4(col));
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::setLabelColor(Label* label, const ImVec4& col)
2020-09-04 17:19:51 +08:00
{
if (label)
{
2021-12-25 10:04:45 +08:00
label->setTextColor({uint8_t(col.x * 255), uint8_t(col.y * 255), uint8_t(col.z * 255), uint8_t(col.w * 255)});
}
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::setLabelColor(Label* label, bool disabled)
2020-09-04 17:19:51 +08:00
{
if (label)
setLabelColor(label, ImGui::GetStyleColorVec4(disabled ? ImGuiCol_TextDisabled : ImGuiCol_Text));
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::setLabelColor(Label* label, ImGuiCol col)
2020-09-04 17:19:51 +08:00
{
if (label && 0 <= col && col < ImGuiCol_COUNT)
setLabelColor(label, ImGui::GetStyleColorVec4(col));
2020-09-04 17:19:51 +08:00
}
ImWchar* ImGuiPresenter::addGlyphRanges(std::string_view key, const std::vector<ImWchar>& ranges)
2020-09-04 17:19:51 +08:00
{
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;
if (ranges.empty())
it->second.push_back(0);
return it->second.data();
2020-09-04 17:19:51 +08:00
}
void ImGuiPresenter::mergeFontGlyphs(ImFont* dst, ImFont* src, ImWchar start, ImWchar end)
2020-09-04 17:19:51 +08:00
{
if (!dst || !src || start > end)
return;
for (auto i = start; i <= end; ++i)
{
const auto g = src->FindGlyphNoFallback(i);
if (g)
{
2020-09-08 16:31:11 +08:00
dst->AddGlyph(nullptr, g->Codepoint, g->X0, g->Y0, g->X1, g->Y1, g->U0, g->V0, g->U1, g->V1, g->AdvanceX);
}
}
dst->BuildLookupTable();
2020-09-04 17:19:51 +08:00
}
int ImGuiPresenter::getCCRefId(Ref* p)
2020-09-04 17:19:51 +08:00
{
2021-12-25 10:04:45 +08:00
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;
2021-12-25 10:04:45 +08:00
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;
2020-09-04 17:19:51 +08:00
}
NS_AX_EXT_END