Add ImGuiEXT test case for PC platforms

This commit is contained in:
halx99 2020-09-08 13:38:16 +08:00
parent d3dfee9614
commit ddbb6bb0b9
10 changed files with 341 additions and 71 deletions

View File

@ -15,7 +15,11 @@ option(BUILD_EXTENSION_COCOSTUDIO "Build extension cocostudio" ON)
option(BUILD_EXTENSION_FAIRYGUI "Build extension FairyGUI" ON)
option(BUILD_EXTENSION_IMGUIEXT "Build extension ImGuiEXT" OFF)
if(WINDOWS OR MACOSX)
option(BUILD_EXTENSION_IMGUIEXT "Build extension ImGuiEXT" ON)
else()
set(BUILD_EXTENSION_IMGUIEXT OFF)
endif()
function(setup_cocos_extension_config target_name)
if(ANDROID)

View File

@ -1,5 +1,7 @@
#include "CCImGuiEXT.h"
#include <assert.h>
#include "imgui_impl_cocos2dx.h"
#include "imgui_internal.h"
NS_CC_EXT_BEGIN
@ -125,17 +127,6 @@ public:
static ImGuiEXT* _instance = nullptr;
std::function<void(ImGuiEXT*)> ImGuiEXT::_onInit;
void ImGuiEXT::init()
{
ImGui_ImplCocos2dx_Init(true);
ImGui::StyleColorsClassic();
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)
@ -152,21 +143,64 @@ void ImGuiEXT::destroyInstance()
{
if (_instance)
{
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT);
eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW);
ImGui_ImplCocos2dx_Shutdown();
_instance->cleanup();
delete _instance;
_instance = nullptr;
}
}
void ImGuiEXT::init()
{
ImGui_ImplCocos2dx_Init(true);
ImGui_ImplCocos2dx_SetCustomFontLoader(&ImGuiEXT::loadCustomFonts, this);
ImGui::StyleColorsClassic();
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->addCustomEventListener(Director::EVENT_BEFORE_DRAW, [=](EventCustom*) { beginFrame(); });
eventDispatcher->addCustomEventListener(Director::EVENT_AFTER_VISIT, [=](EventCustom*) { endFrame(); });
}
void ImGuiEXT::cleanup()
{
auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeCustomEventListeners(Director::EVENT_AFTER_VISIT);
eventDispatcher->removeCustomEventListeners(Director::EVENT_BEFORE_DRAW);
ImGui_ImplCocos2dx_SetCustomFontLoader(nullptr, nullptr);
ImGui_ImplCocos2dx_Shutdown();
CC_SAFE_RELEASE_NULL(_fontsTexture);
}
void ImGuiEXT::setOnInit(const std::function<void(ImGuiEXT*)>& callBack)
{
_onInit = callBack;
}
void ImGuiEXT::loadCustomFonts(void* ud)
{
auto thiz = (ImGuiEXT*)ud;
auto imFonts = ImGui::GetIO().Fonts;
imFonts->Clear();
auto contentZoomFactor = thiz->_contentZoomFactor;
for (auto& fontInfo : thiz->_fontsInfoMap) {
const ImWchar* imChars = nullptr;
switch (fontInfo.second.glyphRange) {
case CHS_GLYPH_RANGE::GENERAL:
imChars = imFonts->GetGlyphRangesChineseSimplifiedCommon();
break;
case CHS_GLYPH_RANGE::FULL:
imChars = imFonts->GetGlyphRangesChineseFull();
break;
}
imFonts->AddFontFromFileTTF(fontInfo.first.c_str(), fontInfo.second.fontSize * contentZoomFactor, nullptr, imChars);
}
}
float ImGuiEXT::scaleAllByDPI(float userScale)
{
// Gets scale
@ -186,7 +220,7 @@ float ImGuiEXT::scaleAllByDPI(float userScale)
}
// Destory font informations, let implcocos2dx recreate at newFrame
ImGui_ImplCocos2dx_DestroyDeviceObjects();
ImGui_ImplCocos2dx_SetDeviceObjectsDirty();
ImGui::GetStyle().ScaleAllSizes(zoomFactor);
@ -198,23 +232,28 @@ float ImGuiEXT::scaleAllByDPI(float userScale)
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;
if (FileUtils::getInstance()->isFileExistInternal(fontFile)) {
_fontsInfoMap.emplace(fontFile, FontInfo{ fontSize, glyphRange });
}
imFonts->AddFontFromFileTTF(fontFile.c_str(), fontSize * _contentZoomFactor, nullptr, imChars);
ImGui_ImplCocos2dx_SetDeviceObjectsDirty();
}
void ImGuiEXT::removeFont(const std::string& fontFile)
{
auto count = _fontsInfoMap.size();
_fontsInfoMap.erase(fontFile);
if(count != _fontsInfoMap.size())
ImGui_ImplCocos2dx_SetDeviceObjectsDirty();
}
void ImGuiEXT::clearFonts()
{
ImGui::GetIO().Fonts->Clear();
_fontsInfoMap.clear();
ImGui_ImplCocos2dx_SetDeviceObjectsDirty();
// auto drawData = ImGui::GetDrawData();
// if(drawData) drawData->Clear();
}
/*
@ -222,22 +261,39 @@ void ImGuiEXT::clearFonts()
*/
void ImGuiEXT::beginFrame()
{
// create frame
ImGui_ImplCocos2dx_NewFrame();
if (!_renderPiplines.empty()) {
// create frame
ImGui_ImplCocos2dx_NewFrame();
// draw all gui
this->update();
// move to endFrame?
_fontsTexture = (Texture2D*)ImGui_ImplCocos2dx_GetFontsTexture();
assert(_fontsTexture != nullptr);
_fontsTexture->retain();
// render
ImGui::Render();
// draw all gui
this->update();
++_beginFrames;
}
}
/*
* flush ImGui draw data to engine
*/
void ImGuiEXT::endFrame() {
ImGui_ImplCocos2dx_RenderDrawData(ImGui::GetDrawData());
ImGui_ImplCocos2dx_RenderPlatform();
if (_beginFrames > 0) {
// render
ImGui::Render();
auto drawData = ImGui::GetDrawData();
if (drawData)
ImGui_ImplCocos2dx_RenderDrawData(drawData);
ImGui_ImplCocos2dx_RenderPlatform();
--_beginFrames;
CC_SAFE_RELEASE_NULL(_fontsTexture);
}
}
void ImGuiEXT::update()
@ -284,6 +340,23 @@ void ImGuiEXT::removeRenderLoop(const std::string& id)
delete tracker;
_renderPiplines.erase(iter);
}
if (_renderPiplines.empty())
deactiveImGuiViewports();
}
void ImGuiEXT::deactiveImGuiViewports() {
ImGuiContext& g = *GImGui;
if (!(g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable))
return;
// Create/resize/destroy platform windows to match each active viewport.
// Skip the main viewport (index 0), which is always fully handled by the application!
for (int i = 1; i < g.Viewports.Size; i++)
{
ImGuiViewportP* viewport = g.Viewports[i];
viewport->Window->Active = false;
}
}
static std::tuple<ImVec2, ImVec2> getTextureUV(Sprite* sp)

View File

@ -1,10 +1,12 @@
#pragma once
#include <stdint.h>
#include <tuple>
#include "cocos2d.h"
#include "ExtensionMacros.h"
#include "imgui/imgui.h"
#include <tuple>
// #define HAVE_IMGUI_MARKDOWN 1
@ -15,6 +17,7 @@ class ImGuiEXT
{
friend class ImGuiEXTRenderer;
void init();
void cleanup();
public:
enum class CHS_GLYPH_RANGE {
@ -46,6 +49,7 @@ public:
/// <param name="fontFile"></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 removeFont(const std::string& fontFile);
void clearFonts();
/// <summary>
@ -128,11 +132,15 @@ public:
#endif
private:
static void loadCustomFonts(void*);
// perform draw ImGui stubs
void beginFrame();
void update();
void endFrame();
static void deactiveImGuiViewports();
private:
static std::function<void(ImGuiEXT*)> _onInit;
@ -149,6 +157,17 @@ private:
std::unordered_map<std::string, std::vector<ImWchar>> glyphRanges;
float _contentZoomFactor = 1.0f;
int64_t _beginFrames = 0;
Texture2D* _fontsTexture = nullptr;
struct FontInfo {
float fontSize;
CHS_GLYPH_RANGE glyphRange;
};
std::unordered_map<std::string, FontInfo> _fontsInfoMap;
};
NS_CC_EXT_END

View File

@ -51,12 +51,16 @@ static GLFWcharfun g_PrevUserCallbackChar = nullptr;
static GLFWmonitorfun g_PrevUserCallbackMonitor = nullptr;
static ImGuiImplCocos2dxLoadFontFun g_loadCustomFont = nullptr;
static void* g_loadCustomFontUserData = nullptr;
// Forward Declarations
static void ImGui_ImplGlfw_InitPlatformInterface();
static void ImGui_ImplGlfw_ShutdownPlatformInterface();
static void ImGui_ImplGlfw_UpdateMonitors();
static bool ImGui_ImplCocos2dx_createShaderPrograms();
#endif // CC_PLATFORM_PC
// fps macro
@ -78,6 +82,7 @@ struct ProgramInfo
};
static ProgramInfo g_ProgramInfo;
static ProgramInfo g_ProgramFontInfo;
static bool g_fontDeviceObjectsDirty = false;
static Texture2D* g_FontTexture = nullptr;
static Mat4 g_Projection;
constexpr IndexFormat g_IndexFormat = sizeof(ImDrawIdx) == 2 ? IndexFormat::U_SHORT : IndexFormat::U_INT;
@ -367,39 +372,42 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
#endif
bool ImGui_ImplCocos2dx_CreateFontsTexture()
void ImGui_ImplCocos2dx_SetCustomFontLoader(ImGuiImplCocos2dxLoadFontFun fun, void* userdata)
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
// Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small)
// because it is more likely to be compatible with user's existing shaders.
// If your ImTextureId represent a higher-level concept than just a GL texture id,
// consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
CC_SAFE_RELEASE(g_FontTexture);
g_FontTexture = new Texture2D();
g_FontTexture->setAntiAliasTexParameters();
g_FontTexture->initWithData(pixels, width*height,
backend::PixelFormat::A8, width, height, Size(width, height));
io.Fonts->TexID = (ImTextureID)g_FontTexture;
return true;
g_loadCustomFont = fun;
g_loadCustomFontUserData = userdata;
}
void ImGui_ImplCocos2dx_DestroyFontsTexture()
void* ImGui_ImplCocos2dx_GetFontsTexture()
{
if (g_FontTexture)
{
ImGui::GetIO().Fonts->TexID = nullptr;
CC_SAFE_DELETE(g_FontTexture);
}
return g_FontTexture;
}
void ImGui_ImplCocos2dx_SetDeviceObjectsDirty()
{
g_fontDeviceObjectsDirty = true;
}
bool ImGui_ImplCocos2dx_CreateDeviceObjects()
{
if (g_loadCustomFont)
g_loadCustomFont(g_loadCustomFontUserData);
ImGui_ImplCocos2dx_createShaderPrograms();
ImGui_ImplCocos2dx_CreateFontsTexture();
g_fontDeviceObjectsDirty = false;
return true;
}
void ImGui_ImplCocos2dx_DestroyDeviceObjects()
{
CC_SAFE_RELEASE_NULL(g_ProgramInfo.program);
CC_SAFE_RELEASE_NULL(g_ProgramFontInfo.program);
ImGui_ImplCocos2dx_DestroyFontsTexture();
}
static bool ImGui_ImplCocos2dx_createShaderPrograms() {
static auto vertex_shader =
"uniform mat4 u_MVPMatrix;\n"
"attribute vec2 a_position;\n"
@ -470,15 +478,38 @@ bool ImGui_ImplCocos2dx_CreateDeviceObjects()
layout.setLayout(sizeof(ImDrawVert));
}
ImGui_ImplCocos2dx_CreateFontsTexture();
return true;
return true;
}
void ImGui_ImplCocos2dx_DestroyDeviceObjects()
bool ImGui_ImplCocos2dx_CreateFontsTexture()
{
CC_SAFE_RELEASE_NULL(g_ProgramInfo.program);
CC_SAFE_RELEASE_NULL(g_ProgramFontInfo.program);
ImGui_ImplCocos2dx_DestroyFontsTexture();
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
// Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small)
// because it is more likely to be compatible with user's existing shaders.
// If your ImTextureId represent a higher-level concept than just a GL texture id,
// consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
CC_SAFE_RELEASE(g_FontTexture);
g_FontTexture = new Texture2D();
g_FontTexture->setAntiAliasTexParameters();
g_FontTexture->initWithData(pixels, width * height,
backend::PixelFormat::A8, width, height, Size(width, height));
io.Fonts->TexID = (ImTextureID)g_FontTexture;
return true;
}
void ImGui_ImplCocos2dx_DestroyFontsTexture()
{
if (g_FontTexture)
{
ImGui::GetIO().Fonts->TexID = nullptr;
CC_SAFE_RELEASE_NULL(g_FontTexture);
}
}
//--------------------------------------------------------------------------------------------------------
@ -962,6 +993,11 @@ void ImGui_ImplCocos2dx_NewFrame()
if (!g_FontTexture)
ImGui_ImplCocos2dx_CreateDeviceObjects();
else if(g_fontDeviceObjectsDirty)
{ // recreate device objects, fonts also should be device objects
ImGui_ImplCocos2dx_DestroyDeviceObjects();
ImGui_ImplCocos2dx_CreateDeviceObjects();
}
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() &&

View File

@ -1,6 +1,8 @@
#pragma once
#include "imgui/imgui.h"
typedef void (*ImGuiImplCocos2dxLoadFontFun)(void* userdata);
IMGUI_IMPL_API bool ImGui_ImplCocos2dx_Init(bool install_callbacks);
IMGUI_IMPL_API void ImGui_ImplCocos2dx_Shutdown();
IMGUI_IMPL_API void ImGui_ImplCocos2dx_NewFrame();
@ -8,7 +10,18 @@ IMGUI_IMPL_API void ImGui_ImplCocos2dx_RenderDrawData(ImDrawData* draw_data)
IMGUI_IMPL_API void ImGui_ImplCocos2dx_RenderPlatform();
// Called by Init/NewFrame/Shutdown
// TODO: maybe hide for internal use only
IMGUI_IMPL_API bool ImGui_ImplCocos2dx_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplCocos2dx_DestroyDeviceObjects();
// TODO: check whether needs public this API
IMGUI_IMPL_API bool ImGui_ImplCocos2dx_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplCocos2dx_DestroyFontsTexture();
// Get FontTexture object cocos2d::Texture2D*
IMGUI_IMPL_API void ImGui_ImplCocos2dx_SetCustomFontLoader(ImGuiImplCocos2dxLoadFontFun fun, void* userdata);
IMGUI_IMPL_API void* ImGui_ImplCocos2dx_GetFontsTexture();
// Sets Device objects dirty
IMGUI_IMPL_API void ImGui_ImplCocos2dx_SetDeviceObjectsDirty();

View File

@ -65,7 +65,7 @@ bool AppDelegate::applicationDidFinishLaunching()
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLViewImpl::create("Cpp Tests");
glview = GLViewImpl::createWithRect("Cpp Tests", Rect(0, 0, 1280, 720));
director->setOpenGLView(glview);
}
@ -80,7 +80,7 @@ bool AppDelegate::applicationDidFinishLaunching()
if (screenSize.height > 320)
{
auto resourceSize = Size(960, 640);
auto resourceSize = Size(1280, 720);
searchPaths.push_back("hd");
searchPaths.push_back("ccs-res/hd");
searchPaths.push_back("ccs-res");

View File

@ -0,0 +1,69 @@
#include "platform/CCPlatformConfig.h"
#include "ImGuiEXTTest.h"
#include "ImGuiEXT/CCImGuiEXT.h"
USING_NS_CC;
USING_NS_CC_EXT;
#if defined(CC_PLATFORM_PC)
static bool show_test_window = true;
static bool show_another_window = false;
static ImVec4 clear_color = ImColor(114, 144, 154);
ImGuiEXTTests::ImGuiEXTTests()
{
ADD_TEST_CASE(ImGuiEXTTest);
}
void ImGuiEXTTest::onEnter()
{
TestCase::onEnter();
ImGuiEXT::getInstance()->addFont(FileUtils::getInstance()->fullPathForFilename("fonts/arial.ttf"));
ImGuiEXT::getInstance()->addRenderLoop("#test", CC_CALLBACK_0(ImGuiEXTTest::onDrawImGui, this), this);
}
void ImGuiEXTTest::onExit()
{
ImGuiEXT::getInstance()->removeRenderLoop("#test");
ImGuiEXT::getInstance()->clearFonts();
ImGuiEXT::destroyInstance();
TestCase::onExit();
}
void ImGuiEXTTest::onDrawImGui()
{
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
{
static float f = 0.0f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_color);
if (ImGui::Button("Test Window")) show_test_window ^= 1;
if (ImGui::Button("Another Window")) show_another_window ^= 1;
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
}
// 2. Show another simple window, this time using an explicit Begin/End pair
if (show_another_window)
{
ImGui::SetNextWindowSize(ImVec2(200, 100), ImGuiCond_FirstUseEver);
ImGui::Begin("Another Window", &show_another_window);
ImGui::Text("Hello");
ImGui::End();
}
// 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
if (show_test_window)
{
ImGui::ShowDemoWindow();
}
}
#endif

View File

@ -0,0 +1,50 @@
/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
Copyright (c) 2020 c4games.com
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef _IMGUIEXT_TEST_H_
#define _IMGUIEXT_TEST_H_
#include "cocos2d.h"
#include "../BaseTest.h"
#if defined(CC_PLATFORM_PC)
DEFINE_TEST_SUITE(ImGuiEXTTests);
class ImGuiEXTTest : public TestCase
{
public:
CREATE_FUNC(ImGuiEXTTest);
std::string title() const { return "ImGuiEXT Test"; }
void onEnter() override;
void onDrawImGui();
void onExit() override;
};
#endif
#endif // _CURL_TEST_H_

View File

@ -44,6 +44,9 @@ public:
RootTests()
{
// addTest("Node: Scene3D", [](){return new (std::nothrow) Scene3DTests(); });
#if defined(CC_PLATFORM_PC)
addTest("ImGuiEXT", []() {return new ImGuiEXTTests(); });
#endif
addTest("Texture2D", []() {return new Texture2DTests(); });
addTest("ActionManager", [](){return new (std::nothrow) ActionManagerTests(); });
addTest("Actions - Basic", [](){ return new (std::nothrow) ActionsTests(); });

View File

@ -119,4 +119,7 @@
#include "ZwoptexTest/ZwoptexTest.h"
#include "SpriteFrameCacheTest/SpriteFrameCacheTest.h"
#include "ZipTest/ZipTests.h"
#if defined(CC_PLATFORM_PC)
#include "ImGuiEXTTest/ImGuiEXTTest.h"
#endif
#endif