mirror of
https://github.com/Astatin3/meteorbot-old.git
synced 2026-06-09 08:38:07 -06:00
Initial commit
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(imgui-node-editor)
|
||||
|
||||
# Define IMGUI_NODE_EDITOR_ROOT_DIR pointing to project root directory
|
||||
get_filename_component(IMGUI_NODE_EDITOR_ROOT_DIR ${CMAKE_SOURCE_DIR}/.. ABSOLUTE CACHE)
|
||||
|
||||
# Enable solution folders in Visual Studio and Folders in Xcode
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Point CMake where to look for module files.
|
||||
list(APPEND CMAKE_MODULE_PATH ${IMGUI_NODE_EDITOR_ROOT_DIR}/misc/cmake-modules)
|
||||
|
||||
# Node editor use C++14
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Macro that will configure an example application
|
||||
macro(add_example_executable name)
|
||||
project(${name})
|
||||
|
||||
set(_Example_Sources
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
#source_group("" FILES ${_Example_Sources})
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${_Example_Sources})
|
||||
|
||||
file(GLOB _Example_CommonResources CONFIGURE_DEPENDS "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data/*")
|
||||
file(GLOB _Example_Resources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
|
||||
#message(FATAL_ERROR "_Example_Resources = ${_Example_Resources}")
|
||||
|
||||
set(_Example_Type)
|
||||
if (WIN32)
|
||||
set(_Example_Type WIN32)
|
||||
|
||||
set(ApplicationIcon ${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Icon.ico)
|
||||
file(TO_NATIVE_PATH "${ApplicationIcon}" ApplicationIcon)
|
||||
string(REPLACE "\\" "\\\\" ApplicationIcon "${ApplicationIcon}")
|
||||
configure_file(
|
||||
${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/Application/Support/Resource.rc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Resource.rc
|
||||
)
|
||||
source_group(TREE "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples" FILES ${_Example_CommonResources})
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Example_Resources})
|
||||
list(APPEND _Example_Resources
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Resource.rc
|
||||
${_Example_CommonResources}
|
||||
)
|
||||
source_group("resources" FILES ${CMAKE_CURRENT_BINARY_DIR}/Resource.rc)
|
||||
elseif (APPLE)
|
||||
set(_Example_Type MACOSX_BUNDLE)
|
||||
|
||||
set_source_files_properties(${_Example_Resources} ${_Example_CommonResources} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "Resources/data"
|
||||
)
|
||||
set(_Example_Icon "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Icon.icns")
|
||||
list(APPEND _Example_Resources ${_Example_Icon})
|
||||
set_source_files_properties(${_Example_Icon} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "Resources"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(${name} ${_Example_Type} ${_Example_Sources} ${_Example_Resources} ${_Example_CommonResources})
|
||||
|
||||
find_package(imgui REQUIRED)
|
||||
find_package(imgui_node_editor REQUIRED)
|
||||
target_link_libraries(${name} PRIVATE imgui imgui_node_editor application)
|
||||
|
||||
set(_ExampleBinDir ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
set_target_properties(${name} PROPERTIES
|
||||
FOLDER "examples"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${_ExampleBinDir}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${_ExampleBinDir}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${_ExampleBinDir}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${_ExampleBinDir}"
|
||||
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${_ExampleBinDir}"
|
||||
DEBUG_POSTFIX _d
|
||||
RELWITHDEBINGO_POSTFIX _rd
|
||||
MINSIZEREL_POSTFIX _r
|
||||
VS_DEBUGGER_WORKING_DIRECTORY ${_ExampleBinDir}
|
||||
MACOSX_BUNDLE_INFO_PLIST "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/application/support/Info.plist.in"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${PACKAGE_NAME}"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.sandbox.collisions"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${PACKAGE_VERSION}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}"
|
||||
MACOSX_BUNDLE_ICON_FILE Icon.icns
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${name}
|
||||
PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ARGS ${_ExampleBinDir}/data
|
||||
)
|
||||
|
||||
set(_ResourceRoot ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
foreach(_Resource ROOT "${IMGUI_NODE_EDITOR_ROOT_DIR}/examples/data" ${_Example_CommonResources} ROOT "${CMAKE_CURRENT_SOURCE_DIR}/data" ${_Example_Resources})
|
||||
if (_Resource STREQUAL ROOT)
|
||||
set(_ResourceRoot FALSE)
|
||||
continue()
|
||||
elseif(NOT _ResourceRoot)
|
||||
set(_ResourceRoot ${_Resource})
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if ("${_Resource}" MATCHES "\.DS_Store$")
|
||||
list(REMOVE_ITEM _Example_Resources ${_Resource})
|
||||
list(REMOVE_ITEM _Example_CommonResources ${_Resource})
|
||||
continue()
|
||||
endif()
|
||||
|
||||
file(RELATIVE_PATH _RelResource ${_ResourceRoot} ${_Resource})
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${name}
|
||||
PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ARGS ${_Resource} ${_ExampleBinDir}/data/${_RelResource}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
endmacro()
|
||||
|
||||
add_subdirectory(application)
|
||||
|
||||
add_subdirectory(canvas-example)
|
||||
add_subdirectory(simple-example)
|
||||
add_subdirectory(widgets-example)
|
||||
add_subdirectory(basic-interaction-example)
|
||||
add_subdirectory(blueprints-example)
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
project(application)
|
||||
|
||||
set(_Application_Sources
|
||||
include/application.h
|
||||
source/application.cpp
|
||||
source/entry_point.cpp
|
||||
source/imgui_extra_keys.h
|
||||
source/config.h.in
|
||||
source/setup.h
|
||||
source/platform.h
|
||||
source/platform_win32.cpp
|
||||
source/platform_glfw.cpp
|
||||
source/renderer.h
|
||||
source/renderer_dx11.cpp
|
||||
source/renderer_ogl3.cpp
|
||||
)
|
||||
|
||||
add_library(application STATIC)
|
||||
|
||||
target_include_directories(application PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
find_package(imgui REQUIRED)
|
||||
find_package(stb_image REQUIRED)
|
||||
find_package(ScopeGuard REQUIRED)
|
||||
target_link_libraries(application PUBLIC imgui)
|
||||
target_link_libraries(application PRIVATE stb_image ScopeGuard)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND _Application_Sources
|
||||
source/imgui_impl_dx11.cpp
|
||||
source/imgui_impl_dx11.h
|
||||
source/imgui_impl_win32.cpp
|
||||
source/imgui_impl_win32.h
|
||||
)
|
||||
|
||||
set(_DXSDK_Dir ${IMGUI_NODE_EDITOR_ROOT_DIR}/external/DXSDK)
|
||||
set(_DXSDK_Arch x86)
|
||||
if (${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
set(_DXSDK_Arch x64)
|
||||
endif()
|
||||
|
||||
add_library(dxerr STATIC ${_DXSDK_Dir}/src/dxerr.cpp)
|
||||
target_include_directories(dxerr PUBLIC "${_DXSDK_Dir}/include")
|
||||
set_property(TARGET dxerr PROPERTY FOLDER "external")
|
||||
|
||||
add_library(d3dx11 UNKNOWN IMPORTED)
|
||||
set_target_properties(d3dx11 PROPERTIES
|
||||
IMPORTED_LOCATION "${_DXSDK_Dir}/lib/${_DXSDK_Arch}/d3dx11.lib"
|
||||
IMPORTED_LOCATION_DEBUG "${_DXSDK_Dir}/lib/${_DXSDK_Arch}/d3dx11d.lib"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_DXSDK_Dir}/include"
|
||||
INTERFACE_LINK_LIBRARIES "$<$<CONFIG:Debug>:dxerr>"
|
||||
)
|
||||
|
||||
target_link_libraries(application PRIVATE d3d11.lib d3dcompiler.lib d3dx11)
|
||||
else()
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(glfw3 3 REQUIRED)
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries(application PRIVATE
|
||||
"-framework CoreFoundation"
|
||||
"-framework Cocoa"
|
||||
"-framework IOKit"
|
||||
"-framework CoreVideo"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (OpenGL_FOUND)
|
||||
set(HAVE_OPENGL YES)
|
||||
|
||||
find_package(gl3w REQUIRED)
|
||||
# Explicitly select embedded GL3W loader
|
||||
target_compile_definitions(application PRIVATE IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
|
||||
target_include_directories(application PRIVATE ${OPENGL_INCLUDE_DIR})
|
||||
target_link_libraries(application PRIVATE ${OPENGL_gl_LIBRARY} gl3w)
|
||||
list(APPEND _Application_Sources
|
||||
source/imgui_impl_opengl3.cpp
|
||||
source/imgui_impl_opengl3.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (glfw3_FOUND)
|
||||
set(HAVE_GLFW3 YES)
|
||||
|
||||
list(APPEND _Application_Sources
|
||||
source/imgui_impl_glfw.cpp
|
||||
source/imgui_impl_glfw.h
|
||||
)
|
||||
target_link_libraries(application PRIVATE
|
||||
glfw
|
||||
)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
source/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/source/config.h
|
||||
)
|
||||
|
||||
target_compile_definitions(application PRIVATE
|
||||
#BACKEND_CONFIG=IMGUI_GLFW
|
||||
#RENDERER_CONFIG=IMGUI_OGL3
|
||||
)
|
||||
|
||||
target_include_directories(application PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/source)
|
||||
|
||||
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${_Application_Sources})
|
||||
|
||||
target_sources(application PRIVATE ${_Application_Sources})
|
||||
|
||||
set_property(TARGET application PROPERTY FOLDER "examples")
|
||||
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
# pragma once
|
||||
# include <imgui.h>
|
||||
# include <string>
|
||||
# include <memory>
|
||||
|
||||
struct Platform;
|
||||
struct Renderer;
|
||||
|
||||
struct Application
|
||||
{
|
||||
Application(const char* name);
|
||||
Application(const char* name, int argc, char** argv);
|
||||
~Application();
|
||||
|
||||
bool Create(int width = -1, int height = -1);
|
||||
|
||||
int Run();
|
||||
|
||||
void SetTitle(const char* title);
|
||||
|
||||
bool Close();
|
||||
void Quit();
|
||||
|
||||
const std::string& GetName() const;
|
||||
|
||||
ImFont* DefaultFont() const;
|
||||
ImFont* HeaderFont() const;
|
||||
|
||||
ImTextureID LoadTexture(const char* path);
|
||||
ImTextureID CreateTexture(const void* data, int width, int height);
|
||||
void DestroyTexture(ImTextureID texture);
|
||||
int GetTextureWidth(ImTextureID texture);
|
||||
int GetTextureHeight(ImTextureID texture);
|
||||
|
||||
virtual void OnStart() {}
|
||||
virtual void OnStop() {}
|
||||
virtual void OnFrame(float deltaTime) {}
|
||||
|
||||
virtual ImGuiWindowFlags GetWindowFlags() const;
|
||||
|
||||
virtual bool CanClose() { return true; }
|
||||
|
||||
private:
|
||||
void RecreateFontAtlas();
|
||||
|
||||
void Frame();
|
||||
|
||||
std::string m_Name;
|
||||
std::string m_IniFilename;
|
||||
std::unique_ptr<Platform> m_Platform;
|
||||
std::unique_ptr<Renderer> m_Renderer;
|
||||
ImGuiContext* m_Context = nullptr;
|
||||
ImFont* m_DefaultFont = nullptr;
|
||||
ImFont* m_HeaderFont = nullptr;
|
||||
};
|
||||
|
||||
int Main(int argc, char** argv);
|
||||
Vendored
+244
@@ -0,0 +1,244 @@
|
||||
# include "application.h"
|
||||
# include "setup.h"
|
||||
# include "platform.h"
|
||||
# include "renderer.h"
|
||||
|
||||
extern "C" {
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_STATIC
|
||||
#include "stb_image.h"
|
||||
}
|
||||
|
||||
|
||||
Application::Application(const char* name)
|
||||
: Application(name, 0, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Application::Application(const char* name, int argc, char** argv)
|
||||
: m_Name(name)
|
||||
, m_Platform(CreatePlatform(*this))
|
||||
, m_Renderer(CreateRenderer())
|
||||
{
|
||||
m_Platform->ApplicationStart(argc, argv);
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
m_Renderer->Destroy();
|
||||
|
||||
m_Platform->ApplicationStop();
|
||||
|
||||
if (m_Context)
|
||||
{
|
||||
ImGui::DestroyContext(m_Context);
|
||||
m_Context= nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::Create(int width /*= -1*/, int height /*= -1*/)
|
||||
{
|
||||
m_Context = ImGui::CreateContext();
|
||||
ImGui::SetCurrentContext(m_Context);
|
||||
|
||||
if (!m_Platform->OpenMainWindow("Application", width, height))
|
||||
return false;
|
||||
|
||||
if (!m_Renderer->Create(*m_Platform))
|
||||
return false;
|
||||
|
||||
m_IniFilename = m_Name + ".ini";
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.IniFilename = m_IniFilename.c_str();
|
||||
io.LogFilename = nullptr;
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
RecreateFontAtlas();
|
||||
|
||||
m_Platform->AcknowledgeWindowScaleChanged();
|
||||
m_Platform->AcknowledgeFramebufferScaleChanged();
|
||||
|
||||
OnStart();
|
||||
|
||||
Frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Application::Run()
|
||||
{
|
||||
m_Platform->ShowMainWindow();
|
||||
|
||||
while (m_Platform->ProcessMainWindowEvents())
|
||||
{
|
||||
if (!m_Platform->IsMainWindowVisible())
|
||||
continue;
|
||||
|
||||
Frame();
|
||||
}
|
||||
|
||||
OnStop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Application::RecreateFontAtlas()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
IM_DELETE(io.Fonts);
|
||||
|
||||
io.Fonts = IM_NEW(ImFontAtlas);
|
||||
|
||||
ImFontConfig config;
|
||||
config.OversampleH = 4;
|
||||
config.OversampleV = 4;
|
||||
config.PixelSnapH = false;
|
||||
|
||||
m_DefaultFont = io.Fonts->AddFontFromFileTTF("data/Play-Regular.ttf", 18.0f, &config);
|
||||
m_HeaderFont = io.Fonts->AddFontFromFileTTF("data/Cuprum-Bold.ttf", 20.0f, &config);
|
||||
|
||||
io.Fonts->Build();
|
||||
}
|
||||
|
||||
void Application::Frame()
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
if (m_Platform->HasWindowScaleChanged())
|
||||
m_Platform->AcknowledgeWindowScaleChanged();
|
||||
|
||||
if (m_Platform->HasFramebufferScaleChanged())
|
||||
{
|
||||
RecreateFontAtlas();
|
||||
m_Platform->AcknowledgeFramebufferScaleChanged();
|
||||
}
|
||||
|
||||
const float windowScale = m_Platform->GetWindowScale();
|
||||
const float framebufferScale = m_Platform->GetFramebufferScale();
|
||||
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
io.MousePos.x *= windowScale;
|
||||
io.MousePos.y *= windowScale;
|
||||
}
|
||||
|
||||
m_Platform->NewFrame();
|
||||
|
||||
// Don't touch "uninitialized" mouse position
|
||||
if (io.MousePos.x > -FLT_MAX && io.MousePos.y > -FLT_MAX)
|
||||
{
|
||||
io.MousePos.x /= windowScale;
|
||||
io.MousePos.y /= windowScale;
|
||||
}
|
||||
io.DisplaySize.x /= windowScale;
|
||||
io.DisplaySize.y /= windowScale;
|
||||
|
||||
io.DisplayFramebufferScale.x = framebufferScale;
|
||||
io.DisplayFramebufferScale.y = framebufferScale;
|
||||
|
||||
m_Renderer->NewFrame();
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetNextWindowSize(io.DisplaySize);
|
||||
const auto windowBorderSize = ImGui::GetStyle().WindowBorderSize;
|
||||
const auto windowRounding = ImGui::GetStyle().WindowRounding;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::Begin("Content", nullptr, GetWindowFlags());
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, windowBorderSize);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, windowRounding);
|
||||
|
||||
OnFrame(io.DeltaTime);
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
// Rendering
|
||||
m_Renderer->Clear(ImColor(32, 32, 32, 255));
|
||||
ImGui::Render();
|
||||
m_Renderer->RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
m_Platform->FinishFrame();
|
||||
}
|
||||
|
||||
void Application::SetTitle(const char* title)
|
||||
{
|
||||
m_Platform->SetMainWindowTitle(title);
|
||||
}
|
||||
|
||||
bool Application::Close()
|
||||
{
|
||||
return m_Platform->CloseMainWindow();
|
||||
}
|
||||
|
||||
void Application::Quit()
|
||||
{
|
||||
m_Platform->Quit();
|
||||
}
|
||||
|
||||
const std::string& Application::GetName() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
ImFont* Application::DefaultFont() const
|
||||
{
|
||||
return m_DefaultFont;
|
||||
}
|
||||
|
||||
ImFont* Application::HeaderFont() const
|
||||
{
|
||||
return m_HeaderFont;
|
||||
}
|
||||
|
||||
ImTextureID Application::LoadTexture(const char* path)
|
||||
{
|
||||
int width = 0, height = 0, component = 0;
|
||||
if (auto data = stbi_load(path, &width, &height, &component, 4))
|
||||
{
|
||||
auto texture = CreateTexture(data, width, height);
|
||||
stbi_image_free(data);
|
||||
return texture;
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ImTextureID Application::CreateTexture(const void* data, int width, int height)
|
||||
{
|
||||
return m_Renderer->CreateTexture(data, width, height);
|
||||
}
|
||||
|
||||
void Application::DestroyTexture(ImTextureID texture)
|
||||
{
|
||||
m_Renderer->DestroyTexture(texture);
|
||||
}
|
||||
|
||||
int Application::GetTextureWidth(ImTextureID texture)
|
||||
{
|
||||
return m_Renderer->GetTextureWidth(texture);
|
||||
}
|
||||
|
||||
int Application::GetTextureHeight(ImTextureID texture)
|
||||
{
|
||||
return m_Renderer->GetTextureHeight(texture);
|
||||
}
|
||||
|
||||
ImGuiWindowFlags Application::GetWindowFlags() const
|
||||
{
|
||||
return
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse |
|
||||
ImGuiWindowFlags_NoSavedSettings |
|
||||
ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
# pragma once
|
||||
|
||||
# cmakedefine01 HAVE_GLFW3
|
||||
# cmakedefine01 HAVE_OPENGL
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
# include "application.h"
|
||||
# include "platform.h"
|
||||
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define NOMINMAX
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <stdlib.h> // __argc, argv
|
||||
# endif
|
||||
|
||||
# if defined(_WIN32) && !defined(_CONSOLE)
|
||||
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
|
||||
{
|
||||
return Main(__argc, __argv);
|
||||
}
|
||||
# else
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
return Main(argc, argv);
|
||||
}
|
||||
# endif
|
||||
Vendored
+65
@@ -0,0 +1,65 @@
|
||||
# pragma once
|
||||
# include <imgui.h>
|
||||
|
||||
# if !defined(IMGUI_VERSION_NUM) || (IMGUI_VERSION_NUM < 18822)
|
||||
|
||||
# include <type_traits>
|
||||
|
||||
// https://stackoverflow.com/a/8597498
|
||||
# define DECLARE_HAS_NESTED(Name, Member) \
|
||||
\
|
||||
template<class T> \
|
||||
struct has_nested_ ## Name \
|
||||
{ \
|
||||
typedef char yes; \
|
||||
typedef yes(&no)[2]; \
|
||||
\
|
||||
template<class U> static yes test(decltype(U::Member)*); \
|
||||
template<class U> static no test(...); \
|
||||
\
|
||||
static bool const value = sizeof(test<T>(0)) == sizeof(yes); \
|
||||
};
|
||||
|
||||
# define DECLARE_KEY_TESTER(Key) \
|
||||
DECLARE_HAS_NESTED(Key, Key) \
|
||||
struct KeyTester_ ## Key \
|
||||
{ \
|
||||
template <typename T> \
|
||||
static int Get(typename std::enable_if<has_nested_ ## Key<ImGuiKey_>::value, T>::type*) \
|
||||
{ \
|
||||
return T::Key; \
|
||||
} \
|
||||
\
|
||||
template <typename T> \
|
||||
static int Get(typename std::enable_if<!has_nested_ ## Key<ImGuiKey_>::value, T>::type*) \
|
||||
{ \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
DECLARE_KEY_TESTER(ImGuiKey_F);
|
||||
DECLARE_KEY_TESTER(ImGuiKey_D);
|
||||
|
||||
static inline int GetEnumValueForF()
|
||||
{
|
||||
return KeyTester_ImGuiKey_F::Get<ImGuiKey_>(nullptr);
|
||||
}
|
||||
|
||||
static inline int GetEnumValueForD()
|
||||
{
|
||||
return KeyTester_ImGuiKey_D::Get<ImGuiKey_>(nullptr);
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
static inline ImGuiKey GetEnumValueForF()
|
||||
{
|
||||
return ImGuiKey_F;
|
||||
}
|
||||
|
||||
static inline ImGuiKey GetEnumValueForD()
|
||||
{
|
||||
return ImGuiKey_D;
|
||||
}
|
||||
|
||||
# endif
|
||||
Vendored
+681
@@ -0,0 +1,681 @@
|
||||
// dear imgui: Renderer for DirectX11
|
||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
|
||||
// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
|
||||
// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2016-05-07: DirectX11: Disabling depth-write.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
|
||||
// DirectX
|
||||
struct IUnknown;
|
||||
#include <stdio.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||
#endif
|
||||
|
||||
struct TEXTURE;
|
||||
|
||||
// DirectX data
|
||||
static ID3D11Device* g_pd3dDevice = NULL;
|
||||
static ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
|
||||
static IDXGIFactory* g_pFactory = NULL;
|
||||
static ID3D11Buffer* g_pVB = NULL;
|
||||
static ID3D11Buffer* g_pIB = NULL;
|
||||
static ID3D10Blob* g_pVertexShaderBlob = NULL;
|
||||
static ID3D11VertexShader* g_pVertexShader = NULL;
|
||||
static ID3D11InputLayout* g_pInputLayout = NULL;
|
||||
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
||||
static ID3D10Blob* g_pPixelShaderBlob = NULL;
|
||||
static ID3D11PixelShader* g_pPixelShader = NULL;
|
||||
static ID3D11SamplerState* g_pFontSampler = NULL;
|
||||
static ImTextureID g_pFontTextureID = NULL;
|
||||
static ID3D11RasterizerState* g_pRasterizerState = NULL;
|
||||
static ID3D11BlendState* g_pBlendState = NULL;
|
||||
static ID3D11DepthStencilState* g_pDepthStencilState = NULL;
|
||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||
static ImVector<TEXTURE*> g_Textures;
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
struct TEXTURE
|
||||
{
|
||||
TEXTURE()
|
||||
{
|
||||
View = NULL;
|
||||
Width = 0;
|
||||
Height = 0;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* View;
|
||||
int Width;
|
||||
int Height;
|
||||
ImVector<unsigned char> Data;
|
||||
};
|
||||
|
||||
// Forward Declarations
|
||||
static bool ImGui_UploadTexture(TEXTURE* texture);
|
||||
static void ImGui_ReleaseTexture(TEXTURE* texture);
|
||||
|
||||
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx)
|
||||
{
|
||||
// Setup viewport
|
||||
D3D11_VIEWPORT vp;
|
||||
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||
vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x;
|
||||
vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = vp.TopLeftY = 0;
|
||||
ctx->RSSetViewports(1, &vp);
|
||||
|
||||
// Setup shader and vertex buffers
|
||||
unsigned int stride = sizeof(ImDrawVert);
|
||||
unsigned int offset = 0;
|
||||
ctx->IASetInputLayout(g_pInputLayout);
|
||||
ctx->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
||||
ctx->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ctx->VSSetShader(g_pVertexShader, NULL, 0);
|
||||
ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
||||
ctx->PSSetShader(g_pPixelShader, NULL, 0);
|
||||
ctx->PSSetSamplers(0, 1, &g_pFontSampler);
|
||||
|
||||
// Setup blend state
|
||||
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||
ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff);
|
||||
ctx->OMSetDepthStencilState(g_pDepthStencilState, 0);
|
||||
ctx->RSSetState(g_pRasterizerState);
|
||||
}
|
||||
|
||||
// Render function
|
||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
ID3D11DeviceContext* ctx = g_pd3dDeviceContext;
|
||||
|
||||
// Create and grow vertex/index buffers if needed
|
||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount)
|
||||
{
|
||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
D3D11_BUFFER_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.ByteWidth = g_VertexBufferSize * sizeof(ImDrawVert);
|
||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
desc.MiscFlags = 0;
|
||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
|
||||
return;
|
||||
}
|
||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount)
|
||||
{
|
||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
D3D11_BUFFER_DESC desc;
|
||||
memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx);
|
||||
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pIB) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload vertex/index data into a single contiguous GPU buffer
|
||||
D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
|
||||
if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
|
||||
return;
|
||||
if (ctx->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
|
||||
return;
|
||||
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
|
||||
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
ctx->Unmap(g_pVB, 0);
|
||||
ctx->Unmap(g_pIB, 0);
|
||||
|
||||
// Setup orthographic projection matrix into our constant buffer
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE mapped_resource;
|
||||
if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK)
|
||||
return;
|
||||
VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData;
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
float mvp[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||
};
|
||||
memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
|
||||
ctx->Unmap(g_pVertexConstantBuffer, 0);
|
||||
}
|
||||
|
||||
// Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
|
||||
struct BACKUP_DX11_STATE
|
||||
{
|
||||
UINT ScissorRectsCount, ViewportsCount;
|
||||
D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||
D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
|
||||
ID3D11RasterizerState* RS;
|
||||
ID3D11BlendState* BlendState;
|
||||
FLOAT BlendFactor[4];
|
||||
UINT SampleMask;
|
||||
UINT StencilRef;
|
||||
ID3D11DepthStencilState* DepthStencilState;
|
||||
ID3D11ShaderResourceView* PSShaderResource;
|
||||
ID3D11SamplerState* PSSampler;
|
||||
ID3D11PixelShader* PS;
|
||||
ID3D11VertexShader* VS;
|
||||
UINT PSInstancesCount, VSInstancesCount;
|
||||
ID3D11ClassInstance* PSInstances[256], *VSInstances[256]; // 256 is max according to PSSetShader documentation
|
||||
D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
|
||||
ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
|
||||
UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
|
||||
DXGI_FORMAT IndexBufferFormat;
|
||||
ID3D11InputLayout* InputLayout;
|
||||
};
|
||||
BACKUP_DX11_STATE old;
|
||||
old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
|
||||
ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
|
||||
ctx->RSGetViewports(&old.ViewportsCount, old.Viewports);
|
||||
ctx->RSGetState(&old.RS);
|
||||
ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
|
||||
ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
|
||||
ctx->PSGetShaderResources(0, 1, &old.PSShaderResource);
|
||||
ctx->PSGetSamplers(0, 1, &old.PSSampler);
|
||||
old.PSInstancesCount = old.VSInstancesCount = 256;
|
||||
ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
|
||||
ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
|
||||
ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
|
||||
ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology);
|
||||
ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
|
||||
ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
|
||||
ctx->IAGetInputLayout(&old.InputLayout);
|
||||
|
||||
// Setup desired DX state
|
||||
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_idx_offset = 0;
|
||||
int global_vtx_offset = 0;
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplDX11_SetupRenderState(draw_data, ctx);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImVec4 clip_rect;
|
||||
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||
|
||||
// Apply scissor/clipping rectangle
|
||||
const D3D11_RECT r = { (LONG)clip_rect.x, (LONG)clip_rect.y, (LONG)clip_rect.z, (LONG)clip_rect.w };
|
||||
ctx->RSSetScissorRects(1, &r);
|
||||
|
||||
// Bind texture, Draw
|
||||
TEXTURE* texture = (TEXTURE*)pcmd->TextureId;
|
||||
ID3D11ShaderResourceView* textureView = texture ? texture->View : nullptr;
|
||||
ctx->PSSetShaderResources(0, 1, &textureView);
|
||||
ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
// Restore modified DX state
|
||||
ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
|
||||
ctx->RSSetViewports(old.ViewportsCount, old.Viewports);
|
||||
ctx->RSSetState(old.RS); if (old.RS) old.RS->Release();
|
||||
ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
|
||||
ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
|
||||
ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
|
||||
ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
|
||||
ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
|
||||
for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
|
||||
ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
|
||||
ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
|
||||
for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
|
||||
ctx->IASetPrimitiveTopology(old.PrimitiveTopology);
|
||||
ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
|
||||
ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
|
||||
ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
g_pFontTextureID = ImGui_CreateTexture(pixels, width, height);
|
||||
|
||||
io.Fonts->TexID = g_pFontTextureID;
|
||||
|
||||
|
||||
// Create texture sampler
|
||||
{
|
||||
D3D11_SAMPLER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.MipLODBias = 0.f;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.MinLOD = 0.f;
|
||||
desc.MaxLOD = 0.f;
|
||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX11_CreateDeviceObjects()
|
||||
{
|
||||
if (!g_pd3dDevice)
|
||||
return false;
|
||||
if (g_pFontSampler)
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
|
||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||
// If you would like to use this DX11 sample code but remove this dependency you can:
|
||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||
|
||||
// Create the vertex shader
|
||||
{
|
||||
static const char* vertexShader =
|
||||
"cbuffer vertexBuffer : register(b0) \
|
||||
{\
|
||||
float4x4 ProjectionMatrix; \
|
||||
};\
|
||||
struct VS_INPUT\
|
||||
{\
|
||||
float2 pos : POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
PS_INPUT main(VS_INPUT input)\
|
||||
{\
|
||||
PS_INPUT output;\
|
||||
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||
output.col = input.col;\
|
||||
output.uv = input.uv;\
|
||||
return output;\
|
||||
}";
|
||||
|
||||
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_4_0", 0, 0, &g_pVertexShaderBlob, NULL);
|
||||
if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
return false;
|
||||
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
|
||||
return false;
|
||||
|
||||
// Create the input layout
|
||||
D3D11_INPUT_ELEMENT_DESC local_layout[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
||||
return false;
|
||||
|
||||
// Create the constant buffer
|
||||
{
|
||||
D3D11_BUFFER_DESC desc;
|
||||
desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||
desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
desc.MiscFlags = 0;
|
||||
g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the pixel shader
|
||||
{
|
||||
static const char* pixelShader =
|
||||
"struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
sampler sampler0;\
|
||||
Texture2D texture0;\
|
||||
\
|
||||
float4 main(PS_INPUT input) : SV_Target\
|
||||
{\
|
||||
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
|
||||
out_col.rgb *= out_col.a; \
|
||||
return out_col; \
|
||||
}";
|
||||
|
||||
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_4_0", 0, 0, &g_pPixelShaderBlob, NULL);
|
||||
if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
return false;
|
||||
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the blending setup
|
||||
{
|
||||
D3D11_BLEND_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.AlphaToCoverageEnable = false;
|
||||
desc.RenderTarget[0].BlendEnable = true;
|
||||
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
|
||||
}
|
||||
|
||||
// Create the rasterizer state
|
||||
{
|
||||
D3D11_RASTERIZER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.FillMode = D3D11_FILL_SOLID;
|
||||
desc.CullMode = D3D11_CULL_NONE;
|
||||
desc.ScissorEnable = true;
|
||||
desc.DepthClipEnable = true;
|
||||
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
|
||||
}
|
||||
|
||||
// Create depth-stencil State
|
||||
{
|
||||
D3D11_DEPTH_STENCIL_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.DepthEnable = false;
|
||||
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||
desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.StencilEnable = false;
|
||||
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.BackFace = desc.FrontFace;
|
||||
g_pd3dDevice->CreateDepthStencilState(&desc, &g_pDepthStencilState);
|
||||
}
|
||||
|
||||
ImGui_ImplDX11_CreateFontsTexture();
|
||||
|
||||
for (auto& texture : g_Textures)
|
||||
ImGui_UploadTexture(texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_InvalidateDeviceObjects()
|
||||
{
|
||||
if (!g_pd3dDevice)
|
||||
return;
|
||||
|
||||
for (auto& texture : g_Textures)
|
||||
ImGui_ReleaseTexture(texture);
|
||||
|
||||
if (g_pFontTextureID)
|
||||
{
|
||||
ImGui_DestroyTexture(g_pFontTextureID);
|
||||
g_pFontTextureID = NULL;
|
||||
}
|
||||
|
||||
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
|
||||
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
|
||||
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
|
||||
|
||||
if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
|
||||
if (g_pDepthStencilState) { g_pDepthStencilState->Release(); g_pDepthStencilState = NULL; }
|
||||
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
|
||||
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
|
||||
if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
|
||||
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }
|
||||
if (g_pInputLayout) { g_pInputLayout->Release(); g_pInputLayout = NULL; }
|
||||
if (g_pVertexShader) { g_pVertexShader->Release(); g_pVertexShader = NULL; }
|
||||
if (g_pVertexShaderBlob) { g_pVertexShaderBlob->Release(); g_pVertexShaderBlob = NULL; }
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
|
||||
{
|
||||
// Setup back-end capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_dx11";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
|
||||
// Get factory from device
|
||||
IDXGIDevice* pDXGIDevice = NULL;
|
||||
IDXGIAdapter* pDXGIAdapter = NULL;
|
||||
IDXGIFactory* pFactory = NULL;
|
||||
|
||||
if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
|
||||
if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
|
||||
if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
|
||||
{
|
||||
g_pd3dDevice = device;
|
||||
g_pd3dDeviceContext = device_context;
|
||||
g_pFactory = pFactory;
|
||||
}
|
||||
if (pDXGIDevice) pDXGIDevice->Release();
|
||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||
g_pd3dDevice->AddRef();
|
||||
g_pd3dDeviceContext->AddRef();
|
||||
|
||||
g_Textures.reserve(16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_Shutdown()
|
||||
{
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
if (g_pFactory) { g_pFactory->Release(); g_pFactory = NULL; }
|
||||
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
|
||||
if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = NULL; }
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_NewFrame()
|
||||
{
|
||||
if (!g_pFontSampler)
|
||||
ImGui_ImplDX11_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_STATIC
|
||||
#include "stb_image.h"
|
||||
}
|
||||
|
||||
ImTextureID ImGui_LoadTexture(const char* path)
|
||||
{
|
||||
int width = 0, height = 0, component = 0;
|
||||
if (auto data = stbi_load(path, &width, &height, &component, 4))
|
||||
{
|
||||
auto texture = ImGui_CreateTexture(data, width, height);
|
||||
stbi_image_free(data);
|
||||
return texture;
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ImTextureID ImGui_CreateTexture(const void* data, int width, int height)
|
||||
{
|
||||
auto texture = IM_NEW(TEXTURE);
|
||||
texture->Width = width;
|
||||
texture->Height = height;
|
||||
texture->Data.resize(width * height * 4);
|
||||
memcpy(texture->Data.Data, data, texture->Data.Size);
|
||||
|
||||
if (!ImGui_UploadTexture(texture))
|
||||
{
|
||||
IM_DELETE(texture);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
g_Textures.push_back(texture);
|
||||
|
||||
return (ImTextureID)texture;
|
||||
}
|
||||
|
||||
void ImGui_DestroyTexture(ImTextureID texture)
|
||||
{
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
TEXTURE* texture_object = (TEXTURE*)(texture);
|
||||
|
||||
ImGui_ReleaseTexture(texture_object);
|
||||
|
||||
for (TEXTURE** it = g_Textures.begin(), **itEnd = g_Textures.end(); it != itEnd; ++it)
|
||||
{
|
||||
if (*it == texture_object)
|
||||
{
|
||||
g_Textures.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IM_DELETE(texture_object);
|
||||
}
|
||||
|
||||
static bool ImGui_UploadTexture(TEXTURE* texture)
|
||||
{
|
||||
if (!g_pd3dDevice || !texture)
|
||||
return false;
|
||||
|
||||
if (texture->View)
|
||||
return true;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = texture->Width;
|
||||
desc.Height = texture->Height;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
desc.CPUAccessFlags = 0;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA subResource = {};
|
||||
subResource.pSysMem = texture->Data.Data;
|
||||
subResource.SysMemPitch = desc.Width * 4;
|
||||
subResource.SysMemSlicePitch = 0;
|
||||
|
||||
ID3D11Texture2D *pTexture = nullptr;
|
||||
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||
|
||||
if (!pTexture)
|
||||
return false;
|
||||
|
||||
// Create texture view
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
|
||||
g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &texture->View);
|
||||
pTexture->Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ImGui_ReleaseTexture(TEXTURE* texture)
|
||||
{
|
||||
if (texture)
|
||||
{
|
||||
if (texture->View)
|
||||
{
|
||||
texture->View->Release();
|
||||
texture->View = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ImGui_GetTextureWidth(ImTextureID texture)
|
||||
{
|
||||
if (TEXTURE* tex = (TEXTURE*)(texture))
|
||||
return tex->Width;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImGui_GetTextureHeight(ImTextureID texture)
|
||||
{
|
||||
if (TEXTURE* tex = (TEXTURE*)(texture))
|
||||
return tex->Height;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
// dear imgui: Renderer for DirectX11
|
||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing ImGui state.
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
|
||||
|
||||
IMGUI_IMPL_API ImTextureID ImGui_LoadTexture(const char* path);
|
||||
IMGUI_IMPL_API ImTextureID ImGui_CreateTexture(const void* data, int width, int height);
|
||||
IMGUI_IMPL_API void ImGui_DestroyTexture(ImTextureID texture);
|
||||
IMGUI_IMPL_API int ImGui_GetTextureWidth(ImTextureID texture);
|
||||
IMGUI_IMPL_API int ImGui_GetTextureHeight(ImTextureID texture);
|
||||
Vendored
+382
@@ -0,0 +1,382 @@
|
||||
// dear imgui: Platform Binding for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
// (Requires: GLFW 3.1+)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
|
||||
// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
|
||||
// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
|
||||
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
|
||||
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
|
||||
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
|
||||
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
|
||||
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_extra_keys.h"
|
||||
|
||||
// GLFW
|
||||
#include <GLFW/glfw3.h>
|
||||
#ifdef _WIN32
|
||||
#undef APIENTRY
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||
#endif
|
||||
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
|
||||
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
|
||||
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||
#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||
#else
|
||||
#define GLFW_HAS_NEW_CURSORS (0)
|
||||
#endif
|
||||
|
||||
// Data
|
||||
enum GlfwClientApi
|
||||
{
|
||||
GlfwClientApi_Unknown,
|
||||
GlfwClientApi_OpenGL,
|
||||
GlfwClientApi_Vulkan
|
||||
};
|
||||
static GLFWwindow* g_Window = NULL; // Main window
|
||||
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
|
||||
static double g_Time = 0.0;
|
||||
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
|
||||
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
|
||||
static bool g_InstalledCallbacks = false;
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL;
|
||||
static GLFWscrollfun g_PrevUserCallbackScroll = NULL;
|
||||
static GLFWkeyfun g_PrevUserCallbackKey = NULL;
|
||||
static GLFWcharfun g_PrevUserCallbackChar = NULL;
|
||||
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
{
|
||||
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
if (g_PrevUserCallbackMousebutton != NULL)
|
||||
g_PrevUserCallbackMousebutton(window, button, action, mods);
|
||||
|
||||
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
|
||||
g_MouseJustPressed[button] = true;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
if (g_PrevUserCallbackScroll != NULL)
|
||||
g_PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MouseWheelH += (float)xoffset;
|
||||
io.MouseWheel += (float)yoffset;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (g_PrevUserCallbackKey != NULL)
|
||||
g_PrevUserCallbackKey(window, key, scancode, action, mods);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (action == GLFW_PRESS)
|
||||
io.KeysDown[key] = true;
|
||||
if (action == GLFW_RELEASE)
|
||||
io.KeysDown[key] = false;
|
||||
|
||||
// Modifiers are not reliable across systems
|
||||
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||
#ifdef _WIN32
|
||||
io.KeySuper = false;
|
||||
#else
|
||||
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||
{
|
||||
if (g_PrevUserCallbackChar != NULL)
|
||||
g_PrevUserCallbackChar(window, c);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddInputCharacter(c);
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||
{
|
||||
g_Window = window;
|
||||
g_Time = 0.0;
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendPlatformName = "imgui_impl_glfw";
|
||||
|
||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
|
||||
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
|
||||
int f_index = GetEnumValueForF();
|
||||
int d_index = GetEnumValueForD();
|
||||
if (f_index >= 0)
|
||||
io.KeyMap[f_index] = GLFW_KEY_F;
|
||||
if (d_index >= 0)
|
||||
io.KeyMap[d_index] = GLFW_KEY_D;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||
io.ClipboardUserData = g_Window;
|
||||
#if defined(_WIN32)
|
||||
//io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
|
||||
#endif
|
||||
|
||||
// Create mouse cursors
|
||||
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
||||
// GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
|
||||
// Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
|
||||
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
|
||||
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||
#if GLFW_HAS_NEW_CURSORS
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||
#else
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
#endif
|
||||
glfwSetErrorCallback(prev_error_callback);
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
g_PrevUserCallbackMousebutton = NULL;
|
||||
g_PrevUserCallbackScroll = NULL;
|
||||
g_PrevUserCallbackKey = NULL;
|
||||
g_PrevUserCallbackChar = NULL;
|
||||
if (install_callbacks)
|
||||
{
|
||||
g_InstalledCallbacks = true;
|
||||
g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||
g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||
g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||
g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||
}
|
||||
|
||||
g_ClientApi = client_api;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForNone(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_Shutdown()
|
||||
{
|
||||
if (g_InstalledCallbacks)
|
||||
{
|
||||
glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton);
|
||||
glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll);
|
||||
glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey);
|
||||
glfwSetCharCallback(g_Window, g_PrevUserCallbackChar);
|
||||
g_InstalledCallbacks = false;
|
||||
}
|
||||
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
{
|
||||
glfwDestroyCursor(g_MouseCursors[cursor_n]);
|
||||
g_MouseCursors[cursor_n] = NULL;
|
||||
}
|
||||
g_ClientApi = GlfwClientApi_Unknown;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||
{
|
||||
// Update buttons
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
{
|
||||
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
|
||||
g_MouseJustPressed[i] = false;
|
||||
}
|
||||
|
||||
// Update mouse position
|
||||
const ImVec2 mouse_pos_backup = io.MousePos;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
const bool focused = true; // Emscripten
|
||||
#else
|
||||
const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0;
|
||||
#endif
|
||||
if (focused)
|
||||
{
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||
glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateGamepads()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
// Update gamepad inputs
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
|
||||
int axes_count = 0, buttons_count = 0;
|
||||
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
|
||||
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
|
||||
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
|
||||
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
if (axes_count > 0 && buttons_count > 0)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
else
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
glfwGetWindowSize(g_Window, &w, &h);
|
||||
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
if (w > 0 && h > 0)
|
||||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
|
||||
|
||||
// Setup time step
|
||||
double current_time = glfwGetTime();
|
||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
|
||||
g_Time = current_time;
|
||||
|
||||
ImGui_ImplGlfw_UpdateMousePosAndButtons();
|
||||
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplGlfw_UpdateGamepads();
|
||||
}
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
// dear imgui: Platform Binding for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForNone(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
// GLFW callbacks
|
||||
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
|
||||
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
Vendored
+690
@@ -0,0 +1,690 @@
|
||||
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
|
||||
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||
|
||||
//----------------------------------------
|
||||
// OpenGL GLSL GLSL
|
||||
// version version string
|
||||
//----------------------------------------
|
||||
// 2.0 110 "#version 110"
|
||||
// 2.1 120 "#version 120"
|
||||
// 3.0 130 "#version 130"
|
||||
// 3.1 140 "#version 140"
|
||||
// 3.2 150 "#version 150"
|
||||
// 3.3 330 "#version 330 core"
|
||||
// 4.0 400 "#version 400 core"
|
||||
// 4.1 410 "#version 410 core"
|
||||
// 4.2 420 "#version 410 core"
|
||||
// 4.3 430 "#version 430 core"
|
||||
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||
//----------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <stdio.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#include <GLES2/gl2.h>
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
|
||||
#else
|
||||
#include <GLES3/gl3.h> // Use GL ES 3
|
||||
#endif
|
||||
#else
|
||||
// About Desktop OpenGL function loaders:
|
||||
// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||
#include <glad/gl.h> // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||
#ifndef GLFW_INCLUDE_NONE
|
||||
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||
#endif
|
||||
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
|
||||
#include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||
#ifndef GLFW_INCLUDE_NONE
|
||||
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||
#endif
|
||||
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
|
||||
#include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
#else
|
||||
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3) || !defined(GL_VERSION_3_2)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 0
|
||||
#else
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 1
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
|
||||
static GLuint g_FontTexture = 0;
|
||||
static GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||
static GLint g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location
|
||||
static GLuint g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
|
||||
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
// Query for GL version (e.g. 320 for GL 3.2)
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
GLint major, minor;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
g_GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||
#else
|
||||
g_GlVersion = 200; // GLES 2
|
||||
#endif
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (g_GlVersion >= 320)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
|
||||
// Store GLSL version string so we can refer to it later in case we recreate shaders.
|
||||
// Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 100";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 300 es";
|
||||
#elif defined(__APPLE__)
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 150";
|
||||
#else
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 130";
|
||||
#endif
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
|
||||
strcpy(g_GlslVersionString, glsl_version);
|
||||
strcat(g_GlslVersionString, "\n");
|
||||
|
||||
// Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
|
||||
// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
|
||||
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||
// you are likely to get a crash below.
|
||||
// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||
const char* gl_loader = "Unknown";
|
||||
IM_UNUSED(gl_loader);
|
||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
gl_loader = "GL3W";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||
gl_loader = "GLEW";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
gl_loader = "GLAD";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||
gl_loader = "GLAD2";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||
gl_loader = "glbinding2";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||
gl_loader = "glbinding3";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
gl_loader = "custom";
|
||||
#else
|
||||
gl_loader = "none";
|
||||
#endif
|
||||
|
||||
// Make an arbitrary GL call (we don't actually need the result)
|
||||
// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
|
||||
// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
if (!g_ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
{
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
#ifdef GL_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
|
||||
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||
bool clip_origin_lower_left = true;
|
||||
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)
|
||||
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
|
||||
if (current_clip_origin == GL_UPPER_LEFT)
|
||||
clip_origin_lower_left = false;
|
||||
#endif
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||
};
|
||||
glUseProgram(g_ShaderHandle);
|
||||
glUniform1i(g_AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
#ifdef GL_SAMPLER_BINDING
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||
#endif
|
||||
|
||||
(void)vertex_array_object;
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glBindVertexArray(vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||
glEnableVertexAttribArray(g_AttribLocationVtxPos);
|
||||
glEnableVertexAttribArray(g_AttribLocationVtxUV);
|
||||
glEnableVertexAttribArray(g_AttribLocationVtxColor);
|
||||
glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
||||
glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
|
||||
glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0)
|
||||
return;
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||
#ifdef GL_SAMPLER_BINDING
|
||||
GLuint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler);
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||
#endif
|
||||
#ifdef GL_POLYGON_MODE
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
#endif
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
|
||||
// Setup desired GL state
|
||||
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||
GLuint vertex_array_object = 0;
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glGenVertexArrays(1, &vertex_array_object);
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
|
||||
// Upload vertex/index buffers
|
||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec4 clip_rect;
|
||||
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
|
||||
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
|
||||
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
|
||||
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
|
||||
|
||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||
{
|
||||
// Apply scissor/clipping rectangle
|
||||
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (g_GlVersion >= 320)
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
|
||||
else
|
||||
#endif
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the temporary VAO
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glDeleteVertexArrays(1, &vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef GL_SAMPLER_BINDING
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glBindVertexArray(last_vertex_array_object);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef GL_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
#endif
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (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.
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &g_FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
#ifdef GL_UNPACK_ROW_LENGTH
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
|
||||
|
||||
// Restore state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
if (g_FontTexture)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
glDeleteTextures(1, &g_FontTexture);
|
||||
io.Fonts->TexID = 0;
|
||||
g_FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
|
||||
static bool CheckShader(GLuint handle, const char* desc)
|
||||
{
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
|
||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
|
||||
static bool CheckProgram(GLuint handle, const char* desc)
|
||||
{
|
||||
GLint status = 0, log_length = 0;
|
||||
glGetProgramiv(handle, GL_LINK_STATUS, &status);
|
||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if ((GLboolean)status == GL_FALSE)
|
||||
fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
GLint last_vertex_array;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#endif
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
|
||||
|
||||
const GLchar* vertex_shader_glsl_120 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"attribute vec2 Position;\n"
|
||||
"attribute vec2 UV;\n"
|
||||
"attribute vec4 Color;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_130 =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"in vec2 Position;\n"
|
||||
"in vec2 UV;\n"
|
||||
"in vec4 Color;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_glsl_410_core =
|
||||
"layout (location = 0) in vec2 Position;\n"
|
||||
"layout (location = 1) in vec2 UV;\n"
|
||||
"layout (location = 2) in vec4 Color;\n"
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_120 =
|
||||
"#ifdef GL_ES\n"
|
||||
" precision mediump float;\n"
|
||||
"#endif\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
" col.xyz *= col.w;"
|
||||
" gl_FragColor = col;\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_130 =
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
" col.xyz *= col.w;"
|
||||
" gl_FragColor = col;\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
" col.xyz *= col.w;"
|
||||
" gl_FragColor = col;\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_410_core =
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" vec4 col = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
" col.xyz *= col.w;"
|
||||
" gl_FragColor = col;\n"
|
||||
"}\n";
|
||||
|
||||
// Select shaders matching our GLSL versions
|
||||
const GLchar* vertex_shader = NULL;
|
||||
const GLchar* fragment_shader = NULL;
|
||||
if (glsl_version < 130)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_120;
|
||||
fragment_shader = fragment_shader_glsl_120;
|
||||
}
|
||||
else if (glsl_version >= 410)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_410_core;
|
||||
fragment_shader = fragment_shader_glsl_410_core;
|
||||
}
|
||||
else if (glsl_version == 300)
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_300_es;
|
||||
fragment_shader = fragment_shader_glsl_300_es;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertex_shader = vertex_shader_glsl_130;
|
||||
fragment_shader = fragment_shader_glsl_130;
|
||||
}
|
||||
|
||||
// Create shaders
|
||||
const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };
|
||||
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
|
||||
glCompileShader(g_VertHandle);
|
||||
CheckShader(g_VertHandle, "vertex shader");
|
||||
|
||||
const GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };
|
||||
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
|
||||
glCompileShader(g_FragHandle);
|
||||
CheckShader(g_FragHandle, "fragment shader");
|
||||
|
||||
g_ShaderHandle = glCreateProgram();
|
||||
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||
glLinkProgram(g_ShaderHandle);
|
||||
CheckProgram(g_ShaderHandle, "shader program");
|
||||
|
||||
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||
g_AttribLocationVtxPos = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
|
||||
g_AttribLocationVtxUV = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
|
||||
g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
|
||||
|
||||
// Create buffers
|
||||
glGenBuffers(1, &g_VboHandle);
|
||||
glGenBuffers(1, &g_ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
|
||||
if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
|
||||
if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
|
||||
if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
|
||||
if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
|
||||
if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
|
||||
if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
|
||||
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline
|
||||
// - Desktop GL: 2.x 3.x 4.x
|
||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
|
||||
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// About Desktop OpenGL function loaders:
|
||||
// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
|
||||
// Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
|
||||
// You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string.
|
||||
// On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
|
||||
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// (Optional) Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
|
||||
// Specific OpenGL ES versions
|
||||
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||
//#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
|
||||
|
||||
// Attempt to auto-detect the default Desktop GL loader based on available header files.
|
||||
// If auto-detection fails or doesn't select the same GL loader file as used by your application,
|
||||
// you are likely to get a crash in ImGui_ImplOpenGL3_Init().
|
||||
// You can explicitly select a loader by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_ES3) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) \
|
||||
&& !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
|
||||
// Try to detect GLES on matching platforms
|
||||
#if defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
|
||||
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||
|
||||
// Otherwise try to detect supported Desktop OpenGL loaders..
|
||||
#elif defined(__has_include)
|
||||
#if __has_include(<GL/glew.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
|
||||
#elif __has_include(<glad/glad.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
|
||||
#elif __has_include(<glad/gl.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLAD2
|
||||
#elif __has_include(<GL/gl3w.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
|
||||
#elif __has_include(<glbinding/glbinding.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
|
||||
#elif __has_include(<glbinding/Binding.h>)
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
|
||||
#else
|
||||
#error "Cannot detect OpenGL loader!"
|
||||
#endif
|
||||
#else
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_GL3W // Default to GL3W embedded in our repository
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Vendored
+462
@@ -0,0 +1,462 @@
|
||||
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_win32.h"
|
||||
#include "imgui_extra_keys.h"
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// Using XInput library for gamepad (with recent Windows SDK this may leads to executables which won't run on Windows 7)
|
||||
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
#include <XInput.h>
|
||||
#else
|
||||
#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
|
||||
#endif
|
||||
#if defined(_MSC_VER) && !defined(IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT)
|
||||
#pragma comment(lib, "xinput")
|
||||
//#pragma comment(lib, "Xinput9_1_0")
|
||||
#endif
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
|
||||
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
|
||||
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
|
||||
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
|
||||
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
|
||||
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
|
||||
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
|
||||
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
|
||||
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
|
||||
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
|
||||
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
|
||||
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
|
||||
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
|
||||
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
|
||||
|
||||
// Win32 Data
|
||||
static HWND g_hWnd = NULL;
|
||||
static INT64 g_Time = 0;
|
||||
static INT64 g_TicksPerSecond = 0;
|
||||
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||
static bool g_HasGamepad = false;
|
||||
static bool g_WantUpdateHasGamepad = true;
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplWin32_Init(void* hwnd)
|
||||
{
|
||||
if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond))
|
||||
return false;
|
||||
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time))
|
||||
return false;
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
g_hWnd = (HWND)hwnd;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendPlatformName = "imgui_impl_win32";
|
||||
//io.ImeWindowHandle = hwnd;
|
||||
|
||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
|
||||
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
|
||||
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
|
||||
io.KeyMap[ImGuiKey_Home] = VK_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = VK_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
|
||||
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
|
||||
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
|
||||
# if defined(IMGUI_VERSION_NUM) && (IMGUI_VERSION_NUM >= 18604)
|
||||
io.KeyMap[ImGuiKey_KeypadEnter] = VK_RETURN;
|
||||
# else
|
||||
io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
|
||||
# endif
|
||||
io.KeyMap[ImGuiKey_A] = 'A';
|
||||
io.KeyMap[ImGuiKey_C] = 'C';
|
||||
io.KeyMap[ImGuiKey_V] = 'V';
|
||||
io.KeyMap[ImGuiKey_X] = 'X';
|
||||
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||
|
||||
int f_index = GetEnumValueForF();
|
||||
int d_index = GetEnumValueForD();
|
||||
if (f_index >= 0)
|
||||
io.KeyMap[f_index] = 'F';
|
||||
if (d_index >= 0)
|
||||
io.KeyMap[d_index] = 'D';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplWin32_Shutdown()
|
||||
{
|
||||
g_hWnd = (HWND)0;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplWin32_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
|
||||
return false;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
::SetCursor(NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
LPTSTR win32_cursor = IDC_ARROW;
|
||||
switch (imgui_cursor)
|
||||
{
|
||||
case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
|
||||
case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
|
||||
case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
|
||||
case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
|
||||
case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
|
||||
case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
|
||||
case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
|
||||
case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
|
||||
case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
|
||||
}
|
||||
::SetCursor(::LoadCursor(NULL, win32_cursor));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_UpdateMousePos()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
POINT pos = { (int)(io.MousePos.x), (int)(io.MousePos.y) };
|
||||
::ClientToScreen(g_hWnd, &pos);
|
||||
::SetCursorPos(pos.x, pos.y);
|
||||
}
|
||||
|
||||
// Set mouse position
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
POINT pos;
|
||||
if (HWND active_window = ::GetForegroundWindow())
|
||||
if (active_window == g_hWnd || ::IsChild(active_window, g_hWnd))
|
||||
if (::GetCursorPos(&pos) && ::ScreenToClient(g_hWnd, &pos))
|
||||
io.MousePos = ImVec2((float)pos.x, (float)pos.y);
|
||||
}
|
||||
|
||||
// Gamepad navigation mapping
|
||||
static void ImGui_ImplWin32_UpdateGamepads()
|
||||
{
|
||||
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
|
||||
return;
|
||||
|
||||
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
|
||||
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
|
||||
if (g_WantUpdateHasGamepad)
|
||||
{
|
||||
XINPUT_CAPABILITIES caps;
|
||||
g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
|
||||
g_WantUpdateHasGamepad = false;
|
||||
}
|
||||
|
||||
XINPUT_STATE xinput_state;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
|
||||
{
|
||||
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
|
||||
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
|
||||
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
}
|
||||
|
||||
void ImGui_ImplWin32_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
RECT rect;
|
||||
::GetClientRect(g_hWnd, &rect);
|
||||
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
||||
|
||||
// Setup time step
|
||||
INT64 current_time;
|
||||
::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time);
|
||||
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
|
||||
g_Time = current_time;
|
||||
|
||||
// Read keyboard modifiers inputs
|
||||
io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
|
||||
io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
|
||||
io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
|
||||
io.KeySuper = false;
|
||||
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
|
||||
|
||||
// Update OS mouse position
|
||||
ImGui_ImplWin32_UpdateMousePos();
|
||||
|
||||
// Update OS mouse cursor with the cursor requested by imgui
|
||||
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
|
||||
if (g_LastMouseCursor != mouse_cursor)
|
||||
{
|
||||
g_LastMouseCursor = mouse_cursor;
|
||||
ImGui_ImplWin32_UpdateMouseCursor();
|
||||
}
|
||||
|
||||
// Update game controllers (if enabled and available)
|
||||
ImGui_ImplWin32_UpdateGamepads();
|
||||
}
|
||||
|
||||
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
|
||||
#ifndef WM_MOUSEHWHEEL
|
||||
#define WM_MOUSEHWHEEL 0x020E
|
||||
#endif
|
||||
#ifndef DBT_DEVNODES_CHANGED
|
||||
#define DBT_DEVNODES_CHANGED 0x0007
|
||||
#endif
|
||||
|
||||
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
|
||||
// Call from your application's message handler.
|
||||
// When implementing your own back-end, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
||||
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
|
||||
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.
|
||||
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
|
||||
#if 0
|
||||
// Copy this line into your .cpp file to forward declare the function.
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (ImGui::GetCurrentContext() == NULL)
|
||||
return 0;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
switch (msg)
|
||||
{
|
||||
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
|
||||
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
|
||||
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
|
||||
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
|
||||
{
|
||||
int button = 0;
|
||||
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
|
||||
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
|
||||
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
|
||||
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
|
||||
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
|
||||
::SetCapture(hwnd);
|
||||
io.MouseDown[button] = true;
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_XBUTTONUP:
|
||||
{
|
||||
int button = 0;
|
||||
if (msg == WM_LBUTTONUP) { button = 0; }
|
||||
if (msg == WM_RBUTTONUP) { button = 1; }
|
||||
if (msg == WM_MBUTTONUP) { button = 2; }
|
||||
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
|
||||
io.MouseDown[button] = false;
|
||||
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
|
||||
::ReleaseCapture();
|
||||
return 0;
|
||||
}
|
||||
case WM_MOUSEWHEEL:
|
||||
io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||
return 0;
|
||||
case WM_MOUSEHWHEEL:
|
||||
io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
|
||||
return 0;
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
if (wParam < 256)
|
||||
io.KeysDown[wParam] = 1;
|
||||
return 0;
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
if (wParam < 256)
|
||||
io.KeysDown[wParam] = 0;
|
||||
return 0;
|
||||
case WM_CHAR:
|
||||
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||
if (wParam > 0 && wParam < 0x10000)
|
||||
io.AddInputCharacterUTF16((unsigned short)wParam);
|
||||
return 0;
|
||||
case WM_SETCURSOR:
|
||||
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
|
||||
return 1;
|
||||
return 0;
|
||||
case WM_DEVICECHANGE:
|
||||
if ((UINT)wParam == DBT_DEVNODES_CHANGED)
|
||||
g_WantUpdateHasGamepad = true;
|
||||
return 0;
|
||||
case WM_KILLFOCUS:
|
||||
for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++)
|
||||
io.KeysDown[n] = false;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// DPI-related helpers (optional)
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// - Use to enable DPI awareness without having to create an application manifest.
|
||||
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
|
||||
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
|
||||
// If you are trying to implement your own back-end for your own engine, you may ignore that noise.
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Implement some of the functions and types normally declared in recent Windows SDK.
|
||||
#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
|
||||
static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 };
|
||||
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
|
||||
ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||
return ::VerifyVersionInfoW(&osvi, mask, cond);
|
||||
}
|
||||
#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WINBLUE
|
||||
#endif
|
||||
|
||||
#ifndef DPI_ENUMS_DECLARED
|
||||
typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
|
||||
typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;
|
||||
#endif
|
||||
#ifndef _DPI_AWARENESS_CONTEXTS_
|
||||
DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
|
||||
#endif
|
||||
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
|
||||
#endif
|
||||
typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
|
||||
typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
|
||||
typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
|
||||
|
||||
// Helper function to enable DPI awareness without setting up a manifest
|
||||
void ImGui_ImplWin32_EnableDpiAwareness()
|
||||
{
|
||||
// if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer!
|
||||
{
|
||||
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
|
||||
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
|
||||
{
|
||||
SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (IsWindows8Point1OrGreater())
|
||||
{
|
||||
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||
if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
|
||||
{
|
||||
SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
::SetProcessDPIAware();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(NOGDI)
|
||||
#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps()
|
||||
#endif
|
||||
|
||||
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
|
||||
{
|
||||
UINT xdpi = 96, ydpi = 96;
|
||||
static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater();
|
||||
if (bIsWindows8Point1OrGreater)
|
||||
{
|
||||
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
|
||||
if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"))
|
||||
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
|
||||
}
|
||||
#ifndef NOGDI
|
||||
else
|
||||
{
|
||||
const HDC dc = ::GetDC(NULL);
|
||||
xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
|
||||
ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
|
||||
::ReleaseDC(NULL, dc);
|
||||
}
|
||||
#endif
|
||||
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
|
||||
return xdpi / 96.0f;
|
||||
}
|
||||
|
||||
float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
|
||||
{
|
||||
HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications)
|
||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
|
||||
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
|
||||
#pragma once
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
|
||||
|
||||
// Configuration
|
||||
// - Disable gamepad support or linking with xinput.lib
|
||||
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
//#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
|
||||
|
||||
// Win32 message handler your application need to call.
|
||||
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
|
||||
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
|
||||
#if 0
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
// DPI-related helpers (optional)
|
||||
// - Use to enable DPI awareness without having to create an application manifest.
|
||||
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
|
||||
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
|
||||
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
|
||||
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
|
||||
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
|
||||
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
|
||||
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# pragma once
|
||||
# include "setup.h"
|
||||
# include <memory>
|
||||
|
||||
struct Application;
|
||||
struct Renderer;
|
||||
|
||||
struct Platform
|
||||
{
|
||||
virtual ~Platform() {};
|
||||
|
||||
virtual bool ApplicationStart(int argc, char** argv) = 0;
|
||||
virtual void ApplicationStop() = 0;
|
||||
|
||||
virtual bool OpenMainWindow(const char* title, int width, int height) = 0;
|
||||
virtual bool CloseMainWindow() = 0;
|
||||
virtual void* GetMainWindowHandle() const = 0;
|
||||
virtual void SetMainWindowTitle(const char* title) = 0;
|
||||
virtual void ShowMainWindow() = 0;
|
||||
virtual bool ProcessMainWindowEvents() = 0;
|
||||
virtual bool IsMainWindowVisible() const = 0;
|
||||
|
||||
virtual void SetRenderer(Renderer* renderer) = 0;
|
||||
|
||||
virtual void NewFrame() = 0;
|
||||
virtual void FinishFrame() = 0;
|
||||
|
||||
virtual void Quit() = 0;
|
||||
|
||||
bool HasWindowScaleChanged() const { return m_WindowScaleChanged; }
|
||||
void AcknowledgeWindowScaleChanged() { m_WindowScaleChanged = false; }
|
||||
float GetWindowScale() const { return m_WindowScale; }
|
||||
void SetWindowScale(float windowScale)
|
||||
{
|
||||
if (windowScale == m_WindowScale)
|
||||
return;
|
||||
m_WindowScale = windowScale;
|
||||
m_WindowScaleChanged = true;
|
||||
}
|
||||
|
||||
bool HasFramebufferScaleChanged() const { return m_FramebufferScaleChanged; }
|
||||
void AcknowledgeFramebufferScaleChanged() { m_FramebufferScaleChanged = false; }
|
||||
float GetFramebufferScale() const { return m_FramebufferScale; }
|
||||
void SetFramebufferScale(float framebufferScale)
|
||||
{
|
||||
if (framebufferScale == m_FramebufferScale)
|
||||
return;
|
||||
m_FramebufferScale = framebufferScale;
|
||||
m_FramebufferScaleChanged = true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool m_WindowScaleChanged = false;
|
||||
float m_WindowScale = 1.0f;
|
||||
bool m_FramebufferScaleChanged = false;
|
||||
float m_FramebufferScale = 1.0f;
|
||||
};
|
||||
|
||||
std::unique_ptr<Platform> CreatePlatform(Application& application);
|
||||
Vendored
+287
@@ -0,0 +1,287 @@
|
||||
# include "platform.h"
|
||||
# include "setup.h"
|
||||
|
||||
# if BACKEND(IMGUI_GLFW)
|
||||
|
||||
# include "application.h"
|
||||
# include "renderer.h"
|
||||
|
||||
# include <GLFW/glfw3.h>
|
||||
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define GLFW_EXPOSE_NATIVE_WIN32
|
||||
# include <GLFW/glfw3native.h>
|
||||
# endif
|
||||
|
||||
# include <imgui.h>
|
||||
# include "imgui_impl_glfw.h"
|
||||
|
||||
struct PlatformGLFW final
|
||||
: Platform
|
||||
{
|
||||
static PlatformGLFW* s_Instance;
|
||||
|
||||
PlatformGLFW(Application& application);
|
||||
|
||||
bool ApplicationStart(int argc, char** argv) override;
|
||||
void ApplicationStop() override;
|
||||
bool OpenMainWindow(const char* title, int width, int height) override;
|
||||
bool CloseMainWindow() override;
|
||||
void* GetMainWindowHandle() const override;
|
||||
void SetMainWindowTitle(const char* title) override;
|
||||
void ShowMainWindow() override;
|
||||
bool ProcessMainWindowEvents() override;
|
||||
bool IsMainWindowVisible() const override;
|
||||
void SetRenderer(Renderer* renderer) override;
|
||||
void NewFrame() override;
|
||||
void FinishFrame() override;
|
||||
void Quit() override;
|
||||
|
||||
void UpdatePixelDensity();
|
||||
|
||||
Application& m_Application;
|
||||
GLFWwindow* m_Window = nullptr;
|
||||
bool m_QuitRequested = false;
|
||||
bool m_IsMinimized = false;
|
||||
bool m_WasMinimized = false;
|
||||
Renderer* m_Renderer = nullptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<Platform> CreatePlatform(Application& application)
|
||||
{
|
||||
return std::make_unique<PlatformGLFW>(application);
|
||||
}
|
||||
|
||||
PlatformGLFW::PlatformGLFW(Application& application)
|
||||
: m_Application(application)
|
||||
{
|
||||
}
|
||||
|
||||
bool PlatformGLFW::ApplicationStart(int argc, char** argv)
|
||||
{
|
||||
if (!glfwInit())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformGLFW::ApplicationStop()
|
||||
{
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
bool PlatformGLFW::OpenMainWindow(const char* title, int width, int height)
|
||||
{
|
||||
if (m_Window)
|
||||
return false;
|
||||
|
||||
glfwWindowHint(GLFW_VISIBLE, 0);
|
||||
|
||||
using InitializerType = bool (*)(GLFWwindow* window, bool install_callbacks);
|
||||
|
||||
InitializerType initializer = nullptr;
|
||||
|
||||
# if RENDERER(IMGUI_OGL3)
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
# if PLATFORM(MACOS)
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
# ifdef GLFW_COCOA_RETINA_FRAMEBUFFER
|
||||
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GL_TRUE);
|
||||
# endif
|
||||
# ifdef GLFW_COCOA_GRAPHICS_SWITCHING
|
||||
glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GL_TRUE);
|
||||
# endif
|
||||
# endif
|
||||
initializer = &ImGui_ImplGlfw_InitForOpenGL;
|
||||
# else
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
initializer = &ImGui_ImplGlfw_InitForNone;
|
||||
# endif
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GL_TRUE);
|
||||
|
||||
width = width < 0 ? 1440 : width;
|
||||
height = height < 0 ? 800 : height;
|
||||
|
||||
m_Window = glfwCreateWindow(width, height, title, nullptr, nullptr);
|
||||
if (!m_Window)
|
||||
return false;
|
||||
|
||||
if (!initializer || !initializer(m_Window, true))
|
||||
{
|
||||
glfwDestroyWindow(m_Window);
|
||||
m_Window = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetWindowUserPointer(m_Window, this);
|
||||
|
||||
glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window)
|
||||
{
|
||||
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||
if (!self->m_QuitRequested)
|
||||
self->CloseMainWindow();
|
||||
});
|
||||
|
||||
glfwSetWindowIconifyCallback(m_Window, [](GLFWwindow* window, int iconified)
|
||||
{
|
||||
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||
if (iconified)
|
||||
{
|
||||
self->m_IsMinimized = true;
|
||||
self->m_WasMinimized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->m_IsMinimized = false;
|
||||
}
|
||||
});
|
||||
|
||||
auto onFramebuferSizeChanged = [](GLFWwindow* window, int width, int height)
|
||||
{
|
||||
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||
if (self->m_Renderer)
|
||||
{
|
||||
self->m_Renderer->Resize(width, height);
|
||||
self->UpdatePixelDensity();
|
||||
}
|
||||
};
|
||||
|
||||
glfwSetFramebufferSizeCallback(m_Window, onFramebuferSizeChanged);
|
||||
|
||||
auto onWindowContentScaleChanged = [](GLFWwindow* window, float xscale, float yscale)
|
||||
{
|
||||
auto self = reinterpret_cast<PlatformGLFW*>(glfwGetWindowUserPointer(window));
|
||||
self->UpdatePixelDensity();
|
||||
};
|
||||
|
||||
glfwSetWindowContentScaleCallback(m_Window, onWindowContentScaleChanged);
|
||||
|
||||
UpdatePixelDensity();
|
||||
|
||||
glfwMakeContextCurrent(m_Window);
|
||||
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlatformGLFW::CloseMainWindow()
|
||||
{
|
||||
if (m_Window == nullptr)
|
||||
return true;
|
||||
|
||||
auto canClose = m_Application.CanClose();
|
||||
|
||||
glfwSetWindowShouldClose(m_Window, canClose ? 1 : 0);
|
||||
|
||||
return canClose;
|
||||
}
|
||||
|
||||
void* PlatformGLFW::GetMainWindowHandle() const
|
||||
{
|
||||
# if PLATFORM(WINDOWS)
|
||||
return m_Window ? glfwGetWin32Window(m_Window) : nullptr;
|
||||
# else
|
||||
return nullptr;
|
||||
# endif
|
||||
}
|
||||
|
||||
void PlatformGLFW::SetMainWindowTitle(const char* title)
|
||||
{
|
||||
glfwSetWindowTitle(m_Window, title);
|
||||
}
|
||||
|
||||
void PlatformGLFW::ShowMainWindow()
|
||||
{
|
||||
if (m_Window == nullptr)
|
||||
return;
|
||||
|
||||
glfwShowWindow(m_Window);
|
||||
}
|
||||
|
||||
bool PlatformGLFW::ProcessMainWindowEvents()
|
||||
{
|
||||
if (m_Window == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_IsMinimized)
|
||||
glfwWaitEvents();
|
||||
else
|
||||
glfwPollEvents();
|
||||
|
||||
if (m_QuitRequested || glfwWindowShouldClose(m_Window))
|
||||
{
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
|
||||
glfwDestroyWindow(m_Window);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlatformGLFW::IsMainWindowVisible() const
|
||||
{
|
||||
if (m_Window == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_IsMinimized)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformGLFW::SetRenderer(Renderer* renderer)
|
||||
{
|
||||
m_Renderer = renderer;
|
||||
}
|
||||
|
||||
void PlatformGLFW::NewFrame()
|
||||
{
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
if (m_WasMinimized)
|
||||
{
|
||||
ImGui::GetIO().DeltaTime = 0.1e-6f;
|
||||
m_WasMinimized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformGLFW::FinishFrame()
|
||||
{
|
||||
if (m_Renderer)
|
||||
m_Renderer->Present();
|
||||
|
||||
glfwSwapBuffers(m_Window);
|
||||
}
|
||||
|
||||
void PlatformGLFW::Quit()
|
||||
{
|
||||
m_QuitRequested = true;
|
||||
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
void PlatformGLFW::UpdatePixelDensity()
|
||||
{
|
||||
float xscale, yscale;
|
||||
glfwGetWindowContentScale(m_Window, &xscale, &yscale);
|
||||
float scale = xscale > yscale ? xscale : yscale;
|
||||
|
||||
# if PLATFORM(WINDOWS)
|
||||
float windowScale = scale;
|
||||
float framebufferScale = scale;
|
||||
# else
|
||||
float windowScale = 1.0f;
|
||||
float framebufferScale = scale;
|
||||
# endif
|
||||
|
||||
SetWindowScale(windowScale); // this is how windows is scaled, not window content
|
||||
|
||||
SetFramebufferScale(framebufferScale);
|
||||
}
|
||||
|
||||
# endif // BACKEND(IMGUI_GLFW)
|
||||
Vendored
+313
@@ -0,0 +1,313 @@
|
||||
# include "platform.h"
|
||||
# include "setup.h"
|
||||
|
||||
# if BACKEND(IMGUI_WIN32)
|
||||
|
||||
# include "application.h"
|
||||
# include "renderer.h"
|
||||
|
||||
# define NOMINMAX
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# include <string>
|
||||
|
||||
# include <imgui.h>
|
||||
# include "imgui_impl_win32.h"
|
||||
|
||||
# if defined(_UNICODE)
|
||||
std::wstring Utf8ToNative(const std::string& str)
|
||||
{
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), nullptr, 0);
|
||||
std::wstring result(size, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), (wchar_t*)result.data(), size);
|
||||
return result;
|
||||
}
|
||||
# else
|
||||
std::string Utf8ToNative(const std::string& str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
# endif
|
||||
|
||||
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
struct PlatformWin32 final
|
||||
: Platform
|
||||
{
|
||||
static PlatformWin32* s_Instance;
|
||||
|
||||
PlatformWin32(Application& application);
|
||||
|
||||
bool ApplicationStart(int argc, char** argv) override;
|
||||
void ApplicationStop() override;
|
||||
bool OpenMainWindow(const char* title, int width, int height) override;
|
||||
bool CloseMainWindow() override;
|
||||
void* GetMainWindowHandle() const override;
|
||||
void SetMainWindowTitle(const char* title) override;
|
||||
void ShowMainWindow() override;
|
||||
bool ProcessMainWindowEvents() override;
|
||||
bool IsMainWindowVisible() const override;
|
||||
void SetRenderer(Renderer* renderer) override;
|
||||
void NewFrame() override;
|
||||
void FinishFrame() override;
|
||||
void Quit() override;
|
||||
|
||||
void SetDpiScale(float dpiScale);
|
||||
|
||||
LRESULT WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
Application& m_Application;
|
||||
WNDCLASSEX m_WindowClass = {};
|
||||
HWND m_MainWindowHandle = nullptr;
|
||||
bool m_IsMinimized = false;
|
||||
bool m_WasMinimized = false;
|
||||
bool m_CanCloseResult = false;
|
||||
Renderer* m_Renderer = nullptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<Platform> CreatePlatform(Application& application)
|
||||
{
|
||||
return std::make_unique<PlatformWin32>(application);
|
||||
}
|
||||
|
||||
PlatformWin32* PlatformWin32::s_Instance = nullptr;
|
||||
|
||||
PlatformWin32::PlatformWin32(Application& application)
|
||||
: m_Application(application)
|
||||
{
|
||||
}
|
||||
|
||||
bool PlatformWin32::ApplicationStart(int argc, char** argv)
|
||||
{
|
||||
if (s_Instance)
|
||||
return false;
|
||||
|
||||
s_Instance = this;
|
||||
|
||||
auto winProc = [](HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -> LRESULT
|
||||
{
|
||||
return s_Instance->WinProc(hWnd, msg, wParam, lParam);
|
||||
};
|
||||
|
||||
m_WindowClass =
|
||||
{
|
||||
sizeof(WNDCLASSEX),
|
||||
CS_CLASSDC,
|
||||
winProc,
|
||||
0L,
|
||||
0L,
|
||||
GetModuleHandle(nullptr),
|
||||
LoadIcon(GetModuleHandle(nullptr),
|
||||
IDI_APPLICATION),
|
||||
LoadCursor(nullptr, IDC_ARROW),
|
||||
nullptr,
|
||||
nullptr,
|
||||
_T("imgui-node-editor-application"),
|
||||
LoadIcon(GetModuleHandle(nullptr),
|
||||
IDI_APPLICATION)
|
||||
};
|
||||
|
||||
if (!RegisterClassEx(&m_WindowClass))
|
||||
{
|
||||
s_Instance = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGui_ImplWin32_EnableDpiAwareness();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformWin32::ApplicationStop()
|
||||
{
|
||||
if (!s_Instance)
|
||||
return;
|
||||
|
||||
UnregisterClass(m_WindowClass.lpszClassName, m_WindowClass.hInstance);
|
||||
|
||||
s_Instance = nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool PlatformWin32::OpenMainWindow(const char* title, int width, int height)
|
||||
{
|
||||
if (m_MainWindowHandle)
|
||||
return false;
|
||||
|
||||
m_MainWindowHandle = CreateWindow(
|
||||
m_WindowClass.lpszClassName,
|
||||
Utf8ToNative(title).c_str(),
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
width < 0 ? CW_USEDEFAULT : width,
|
||||
height < 0 ? CW_USEDEFAULT : height,
|
||||
nullptr, nullptr, m_WindowClass.hInstance, nullptr);
|
||||
|
||||
if (!m_MainWindowHandle)
|
||||
return false;
|
||||
|
||||
if (!ImGui_ImplWin32_Init(m_MainWindowHandle))
|
||||
{
|
||||
DestroyWindow(m_MainWindowHandle);
|
||||
m_MainWindowHandle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetDpiScale(ImGui_ImplWin32_GetDpiScaleForHwnd(m_MainWindowHandle));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlatformWin32::CloseMainWindow()
|
||||
{
|
||||
if (m_MainWindowHandle == nullptr)
|
||||
return true;
|
||||
|
||||
SendMessage(m_MainWindowHandle, WM_CLOSE, 0, 0);
|
||||
|
||||
return m_CanCloseResult;
|
||||
}
|
||||
|
||||
void* PlatformWin32::GetMainWindowHandle() const
|
||||
{
|
||||
return m_MainWindowHandle;
|
||||
}
|
||||
|
||||
void PlatformWin32::SetMainWindowTitle(const char* title)
|
||||
{
|
||||
SetWindowText(m_MainWindowHandle, Utf8ToNative(title).c_str());
|
||||
}
|
||||
|
||||
void PlatformWin32::ShowMainWindow()
|
||||
{
|
||||
if (m_MainWindowHandle == nullptr)
|
||||
return;
|
||||
|
||||
//ShowWindow(m_MainWindowHandle, SW_SHOWMAXIMIZED);
|
||||
ShowWindow(m_MainWindowHandle, SW_SHOW);
|
||||
UpdateWindow(m_MainWindowHandle);
|
||||
}
|
||||
|
||||
bool PlatformWin32::ProcessMainWindowEvents()
|
||||
{
|
||||
if (m_MainWindowHandle == nullptr)
|
||||
return false;
|
||||
|
||||
auto fetchMessage = [this](MSG* msg) -> bool
|
||||
{
|
||||
if (!m_IsMinimized)
|
||||
return PeekMessage(msg, nullptr, 0U, 0U, PM_REMOVE) != 0;
|
||||
else
|
||||
return GetMessage(msg, nullptr, 0U, 0U) != 0;
|
||||
};
|
||||
|
||||
MSG msg = {};
|
||||
while (fetchMessage(&msg))
|
||||
{
|
||||
if (msg.message == WM_KEYDOWN && (msg.wParam == VK_ESCAPE))
|
||||
PostQuitMessage(0);
|
||||
|
||||
if (msg.message == WM_QUIT)
|
||||
return false;
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlatformWin32::IsMainWindowVisible() const
|
||||
{
|
||||
if (m_MainWindowHandle == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_IsMinimized)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PlatformWin32::SetRenderer(Renderer* renderer)
|
||||
{
|
||||
m_Renderer = renderer;
|
||||
}
|
||||
|
||||
void PlatformWin32::NewFrame()
|
||||
{
|
||||
ImGui_ImplWin32_NewFrame();
|
||||
|
||||
if (m_WasMinimized)
|
||||
{
|
||||
ImGui::GetIO().DeltaTime = 0.1e-6f;
|
||||
m_WasMinimized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformWin32::FinishFrame()
|
||||
{
|
||||
if (m_Renderer)
|
||||
m_Renderer->Present();
|
||||
}
|
||||
|
||||
void PlatformWin32::Quit()
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
void PlatformWin32::SetDpiScale(float dpiScale)
|
||||
{
|
||||
SetWindowScale(dpiScale);
|
||||
SetFramebufferScale(dpiScale);
|
||||
}
|
||||
|
||||
LRESULT PlatformWin32::WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
|
||||
return 1;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
m_CanCloseResult = m_Application.CanClose();
|
||||
if (m_CanCloseResult)
|
||||
{
|
||||
ImGui_ImplWin32_Shutdown();
|
||||
DestroyWindow(hWnd);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_SIZE:
|
||||
if (wParam == SIZE_MINIMIZED)
|
||||
{
|
||||
m_IsMinimized = true;
|
||||
m_WasMinimized = true;
|
||||
}
|
||||
else if (wParam == SIZE_RESTORED && m_IsMinimized)
|
||||
{
|
||||
m_IsMinimized = false;
|
||||
}
|
||||
|
||||
if (m_Renderer != nullptr && wParam != SIZE_MINIMIZED)
|
||||
m_Renderer->Resize(static_cast<int>(LOWORD(lParam)), static_cast<int>(HIWORD(lParam)));
|
||||
return 0;
|
||||
|
||||
case WM_SYSCOMMAND:
|
||||
if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case WM_DPICHANGED:
|
||||
SetDpiScale(ImGui_ImplWin32_GetDpiScaleForHwnd(hWnd));
|
||||
return 0;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
# endif // BACKEND(IMGUI_WIN32)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# pragma once
|
||||
# include "setup.h"
|
||||
# include <memory>
|
||||
|
||||
struct Platform;
|
||||
struct ImDrawData;
|
||||
struct ImVec4;
|
||||
using ImTextureID= void*;
|
||||
|
||||
struct Renderer
|
||||
{
|
||||
virtual ~Renderer() {};
|
||||
|
||||
virtual bool Create(Platform& platform) = 0;
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
virtual void NewFrame() = 0;
|
||||
|
||||
virtual void RenderDrawData(ImDrawData* drawData) = 0;
|
||||
|
||||
virtual void Clear(const ImVec4& color) = 0;
|
||||
virtual void Present() = 0;
|
||||
|
||||
virtual void Resize(int width, int height) = 0;
|
||||
|
||||
virtual ImTextureID CreateTexture(const void* data, int width, int height) = 0;
|
||||
virtual void DestroyTexture(ImTextureID texture) = 0;
|
||||
virtual int GetTextureWidth(ImTextureID texture) = 0;
|
||||
virtual int GetTextureHeight(ImTextureID texture) = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<Renderer> CreateRenderer();
|
||||
Vendored
+195
@@ -0,0 +1,195 @@
|
||||
# include "renderer.h"
|
||||
# include "setup.h"
|
||||
|
||||
# if RENDERER(IMGUI_DX11)
|
||||
|
||||
# include "platform.h"
|
||||
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define NOMINMAX
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# endif
|
||||
|
||||
# include <imgui.h>
|
||||
# include "imgui_impl_dx11.h"
|
||||
# include <d3d11.h>
|
||||
|
||||
|
||||
struct RendererDX11 final
|
||||
: Renderer
|
||||
{
|
||||
bool Create(Platform& platform) override;
|
||||
void Destroy() override;
|
||||
void NewFrame() override;
|
||||
void RenderDrawData(ImDrawData* drawData) override;
|
||||
void Clear(const ImVec4& color) override;
|
||||
void Present() override;
|
||||
void Resize(int width, int height) override;
|
||||
|
||||
ImTextureID CreateTexture(const void* data, int width, int height) override;
|
||||
void DestroyTexture(ImTextureID texture) override;
|
||||
int GetTextureWidth(ImTextureID texture) override;
|
||||
int GetTextureHeight(ImTextureID texture) override;
|
||||
|
||||
HRESULT CreateDeviceD3D(HWND hWnd);
|
||||
void CleanupDeviceD3D();
|
||||
|
||||
void CreateRenderTarget();
|
||||
void CleanupRenderTarget();
|
||||
|
||||
Platform* m_Platform = nullptr;
|
||||
ID3D11Device* m_device = nullptr;
|
||||
ID3D11DeviceContext* m_deviceContext = nullptr;
|
||||
IDXGISwapChain* m_swapChain = nullptr;
|
||||
ID3D11RenderTargetView* m_mainRenderTargetView = nullptr;
|
||||
};
|
||||
|
||||
std::unique_ptr<Renderer> CreateRenderer()
|
||||
{
|
||||
return std::make_unique<RendererDX11>();
|
||||
}
|
||||
|
||||
bool RendererDX11::Create(Platform& platform)
|
||||
{
|
||||
m_Platform = &platform;
|
||||
|
||||
auto hr = CreateDeviceD3D(reinterpret_cast<HWND>(platform.GetMainWindowHandle()));
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
if (!ImGui_ImplDX11_Init(m_device, m_deviceContext))
|
||||
{
|
||||
CleanupDeviceD3D();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Platform->SetRenderer(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RendererDX11::Destroy()
|
||||
{
|
||||
if (!m_Platform)
|
||||
return;
|
||||
|
||||
m_Platform->SetRenderer(nullptr);
|
||||
|
||||
ImGui_ImplDX11_Shutdown();
|
||||
|
||||
CleanupDeviceD3D();
|
||||
}
|
||||
|
||||
void RendererDX11::NewFrame()
|
||||
{
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
}
|
||||
|
||||
void RendererDX11::RenderDrawData(ImDrawData* drawData)
|
||||
{
|
||||
ImGui_ImplDX11_RenderDrawData(drawData);
|
||||
}
|
||||
|
||||
void RendererDX11::Clear(const ImVec4& color)
|
||||
{
|
||||
m_deviceContext->ClearRenderTargetView(m_mainRenderTargetView, (float*)&color.x);
|
||||
}
|
||||
|
||||
void RendererDX11::Present()
|
||||
{
|
||||
m_swapChain->Present(1, 0);
|
||||
}
|
||||
|
||||
void RendererDX11::Resize(int width, int height)
|
||||
{
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
CleanupRenderTarget();
|
||||
m_swapChain->ResizeBuffers(0, (UINT)width, (UINT)height, DXGI_FORMAT_UNKNOWN, 0);
|
||||
CreateRenderTarget();
|
||||
}
|
||||
|
||||
HRESULT RendererDX11::CreateDeviceD3D(HWND hWnd)
|
||||
{
|
||||
// Setup swap chain
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
{
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferCount = 2;
|
||||
sd.BufferDesc.Width = 0;
|
||||
sd.BufferDesc.Height = 0;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = hWnd;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
}
|
||||
|
||||
UINT createDeviceFlags = 0;
|
||||
//createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0, };
|
||||
if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &m_swapChain, &m_device, &featureLevel, &m_deviceContext) != S_OK)
|
||||
return E_FAIL;
|
||||
|
||||
CreateRenderTarget();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void RendererDX11::CleanupDeviceD3D()
|
||||
{
|
||||
CleanupRenderTarget();
|
||||
if (m_swapChain) { m_swapChain->Release(); m_swapChain = nullptr; }
|
||||
if (m_deviceContext) { m_deviceContext->Release(); m_deviceContext = nullptr; }
|
||||
if (m_device) { m_device->Release(); m_device = nullptr; }
|
||||
}
|
||||
|
||||
void RendererDX11::CreateRenderTarget()
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
m_swapChain->GetDesc(&sd);
|
||||
|
||||
// Create the render target
|
||||
ID3D11Texture2D* pBackBuffer;
|
||||
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
|
||||
ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
|
||||
render_target_view_desc.Format = sd.BufferDesc.Format;
|
||||
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
|
||||
m_device->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &m_mainRenderTargetView);
|
||||
m_deviceContext->OMSetRenderTargets(1, &m_mainRenderTargetView, nullptr);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
|
||||
void RendererDX11::CleanupRenderTarget()
|
||||
{
|
||||
if (m_mainRenderTargetView) { m_mainRenderTargetView->Release(); m_mainRenderTargetView = nullptr; }
|
||||
}
|
||||
|
||||
ImTextureID RendererDX11::CreateTexture(const void* data, int width, int height)
|
||||
{
|
||||
return ImGui_CreateTexture(data, width, height);
|
||||
}
|
||||
|
||||
void RendererDX11::DestroyTexture(ImTextureID texture)
|
||||
{
|
||||
return ImGui_DestroyTexture(texture);
|
||||
}
|
||||
|
||||
int RendererDX11::GetTextureWidth(ImTextureID texture)
|
||||
{
|
||||
return ImGui_GetTextureWidth(texture);
|
||||
}
|
||||
|
||||
int RendererDX11::GetTextureHeight(ImTextureID texture)
|
||||
{
|
||||
return ImGui_GetTextureHeight(texture);
|
||||
}
|
||||
|
||||
# endif // RENDERER(IMGUI_DX11)
|
||||
Vendored
+205
@@ -0,0 +1,205 @@
|
||||
# include "renderer.h"
|
||||
|
||||
# if RENDERER(IMGUI_OGL3)
|
||||
|
||||
# include "platform.h"
|
||||
# include <algorithm>
|
||||
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define NOMINMAX
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# endif
|
||||
|
||||
# include "imgui_impl_opengl3.h"
|
||||
|
||||
# if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
# include <GL/gl3w.h> // Initialize with gl3wInit()
|
||||
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||
# include <GL/glew.h> // Initialize with glewInit()
|
||||
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
# include <glad/glad.h> // Initialize with gladLoadGL()
|
||||
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||
# include <glad/gl.h> // Initialize with gladLoadGL(...) or gladLoaderLoadGL()
|
||||
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||
# define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||
# include <glbinding/Binding.h> // Initialize with glbinding::Binding::initialize()
|
||||
# include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
# elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||
# define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
|
||||
# include <glbinding/glbinding.h>// Initialize with glbinding::initialize()
|
||||
# include <glbinding/gl/gl.h>
|
||||
using namespace gl;
|
||||
# else
|
||||
# include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||
# endif
|
||||
|
||||
struct ImTexture
|
||||
{
|
||||
GLuint TextureID = 0;
|
||||
int Width = 0;
|
||||
int Height = 0;
|
||||
};
|
||||
|
||||
struct RendererOpenGL3 final
|
||||
: Renderer
|
||||
{
|
||||
bool Create(Platform& platform) override;
|
||||
void Destroy() override;
|
||||
void NewFrame() override;
|
||||
void RenderDrawData(ImDrawData* drawData) override;
|
||||
void Clear(const ImVec4& color) override;
|
||||
void Present() override;
|
||||
void Resize(int width, int height) override;
|
||||
|
||||
ImVector<ImTexture>::iterator FindTexture(ImTextureID texture);
|
||||
ImTextureID CreateTexture(const void* data, int width, int height) override;
|
||||
void DestroyTexture(ImTextureID texture) override;
|
||||
int GetTextureWidth(ImTextureID texture) override;
|
||||
int GetTextureHeight(ImTextureID texture) override;
|
||||
|
||||
Platform* m_Platform = nullptr;
|
||||
ImVector<ImTexture> m_Textures;
|
||||
};
|
||||
|
||||
std::unique_ptr<Renderer> CreateRenderer()
|
||||
{
|
||||
return std::make_unique<RendererOpenGL3>();
|
||||
}
|
||||
|
||||
bool RendererOpenGL3::Create(Platform& platform)
|
||||
{
|
||||
m_Platform = &platform;
|
||||
|
||||
// Technically we should initialize OpenGL context here,
|
||||
// but for now we relay on one created by GLFW3
|
||||
|
||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
|
||||
bool err = gl3wInit() != 0;
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
|
||||
bool err = glewInit() != GLEW_OK;
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
bool err = gladLoadGL() == 0;
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
|
||||
bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one.
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
|
||||
bool err = false;
|
||||
glbinding::Binding::initialize();
|
||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
|
||||
bool err = false;
|
||||
glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); });
|
||||
#else
|
||||
bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
|
||||
#endif
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
# if PLATFORM(MACOS)
|
||||
const char* glslVersion = "#version 150";
|
||||
# else
|
||||
const char* glslVersion = "#version 130";
|
||||
# endif
|
||||
|
||||
if (!ImGui_ImplOpenGL3_Init(glslVersion))
|
||||
return false;
|
||||
|
||||
m_Platform->SetRenderer(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RendererOpenGL3::Destroy()
|
||||
{
|
||||
if (!m_Platform)
|
||||
return;
|
||||
|
||||
m_Platform->SetRenderer(nullptr);
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
}
|
||||
|
||||
void RendererOpenGL3::NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
}
|
||||
|
||||
void RendererOpenGL3::RenderDrawData(ImDrawData* drawData)
|
||||
{
|
||||
ImGui_ImplOpenGL3_RenderDrawData(drawData);
|
||||
}
|
||||
|
||||
void RendererOpenGL3::Clear(const ImVec4& color)
|
||||
{
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void RendererOpenGL3::Present()
|
||||
{
|
||||
}
|
||||
|
||||
void RendererOpenGL3::Resize(int width, int height)
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
ImTextureID RendererOpenGL3::CreateTexture(const void* data, int width, int height)
|
||||
{
|
||||
m_Textures.resize(m_Textures.size() + 1);
|
||||
ImTexture& texture = m_Textures.back();
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture = 0;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &texture.TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.TextureID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
texture.Width = width;
|
||||
texture.Height = height;
|
||||
|
||||
return reinterpret_cast<ImTextureID>(static_cast<std::intptr_t>(texture.TextureID));
|
||||
}
|
||||
|
||||
ImVector<ImTexture>::iterator RendererOpenGL3::FindTexture(ImTextureID texture)
|
||||
{
|
||||
auto textureID = static_cast<GLuint>(reinterpret_cast<std::intptr_t>(texture));
|
||||
|
||||
return std::find_if(m_Textures.begin(), m_Textures.end(), [textureID](ImTexture& texture)
|
||||
{
|
||||
return texture.TextureID == textureID;
|
||||
});
|
||||
}
|
||||
|
||||
void RendererOpenGL3::DestroyTexture(ImTextureID texture)
|
||||
{
|
||||
auto textureIt = FindTexture(texture);
|
||||
if (textureIt == m_Textures.end())
|
||||
return;
|
||||
|
||||
glDeleteTextures(1, &textureIt->TextureID);
|
||||
|
||||
m_Textures.erase(textureIt);
|
||||
}
|
||||
|
||||
int RendererOpenGL3::GetTextureWidth(ImTextureID texture)
|
||||
{
|
||||
auto textureIt = FindTexture(texture);
|
||||
if (textureIt != m_Textures.end())
|
||||
return textureIt->Width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RendererOpenGL3::GetTextureHeight(ImTextureID texture)
|
||||
{
|
||||
auto textureIt = FindTexture(texture);
|
||||
if (textureIt != m_Textures.end())
|
||||
return textureIt->Height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif // RENDERER(IMGUI_OGL3)
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
# pragma once
|
||||
# include "config.h"
|
||||
|
||||
# define DETAIL_PRIV_EXPAND(x) x
|
||||
# define EXPAND(x) DETAIL_PRIV_EXPAND(x)
|
||||
# define DETAIL_PRIV_CONCAT(x, y) x ## y
|
||||
# define CONCAT(x, y) DETAIL_PRIV_CONCAT(x, y)
|
||||
|
||||
|
||||
// Define PLATFORM(x) which evaluate to 0 or 1 when
|
||||
// 'x' is: WINDOWS, MACOS or LINUX
|
||||
# if defined(_WIN32)
|
||||
# define PLATFORM_PRIV_WINDOWS() 1
|
||||
# elif defined(__APPLE__)
|
||||
# define PLATFORM_PRIV_MACOS() 1
|
||||
# elif defined(__linux__)
|
||||
# define PLATFORM_PRIV_LINUX() 1
|
||||
# else
|
||||
# error Unsupported platform
|
||||
# endif
|
||||
|
||||
# ifndef PLATFORM_PRIV_WINDOWS
|
||||
# define PLATFORM_PRIV_WINDOWS() 0
|
||||
# endif
|
||||
# ifndef PLATFORM_PRIV_MACOS
|
||||
# define PLATFORM_PRIV_MACOS() 0
|
||||
# endif
|
||||
# ifndef PLATFORM_PRIV_LINUX
|
||||
# define PLATFORM_PRIV_LINUX() 0
|
||||
# endif
|
||||
|
||||
# define PLATFORM(x) (PLATFORM_PRIV_##x())
|
||||
|
||||
|
||||
// Define BACKEND(x) which evaluate to 0 or 1 when
|
||||
// 'x' is: IMGUI_WIN32 or IMGUI_GLFW
|
||||
//
|
||||
// Use BACKEND_CONFIG to override desired backend
|
||||
//
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define BACKEND_HAVE_IMGUI_WIN32() 1
|
||||
# endif
|
||||
# if HAVE_GLFW3
|
||||
# define BACKEND_HAVE_IMGUI_GLFW() 1
|
||||
# endif
|
||||
|
||||
# ifndef BACKEND_HAVE_IMGUI_WIN32
|
||||
# define BACKEND_HAVE_IMGUI_WIN32() 0
|
||||
# endif
|
||||
# ifndef BACKEND_HAVE_IMGUI_GLFW
|
||||
# define BACKEND_HAVE_IMGUI_GLFW() 0
|
||||
# endif
|
||||
|
||||
# define BACKEND_PRIV_IMGUI_WIN32() 1
|
||||
# define BACKEND_PRIV_IMGUI_GLFW() 2
|
||||
|
||||
# if !defined(BACKEND_CONFIG)
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define BACKEND_CONFIG IMGUI_WIN32
|
||||
# else
|
||||
# define BACKEND_CONFIG IMGUI_GLFW
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# define BACKEND(x) ((BACKEND_PRIV_##x()) == CONCAT(BACKEND_PRIV_, EXPAND(BACKEND_CONFIG))() && (BACKEND_HAVE_##x()))
|
||||
|
||||
|
||||
// Define RENDERER(x) which evaluate to 0 or 1 when
|
||||
// 'x' is: IMGUI_DX11 or IMGUI_OGL3
|
||||
//
|
||||
// Use RENDERER_CONFIG to override desired renderer
|
||||
//
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define RENDERER_HAVE_IMGUI_DX11() 1
|
||||
# endif
|
||||
# if HAVE_OPENGL
|
||||
# define RENDERER_HAVE_IMGUI_OGL3() 1
|
||||
# endif
|
||||
|
||||
# ifndef RENDERER_HAVE_IMGUI_DX11
|
||||
# define RENDERER_HAVE_IMGUI_DX11() 0
|
||||
# endif
|
||||
# ifndef RENDERER_HAVE_IMGUI_OGL3
|
||||
# define RENDERER_HAVE_IMGUI_OGL3() 0
|
||||
# endif
|
||||
|
||||
# define RENDERER_PRIV_IMGUI_DX11() 1
|
||||
# define RENDERER_PRIV_IMGUI_OGL3() 2
|
||||
|
||||
# if !defined(RENDERER_CONFIG)
|
||||
# if PLATFORM(WINDOWS)
|
||||
# define RENDERER_CONFIG IMGUI_DX11
|
||||
# else
|
||||
# define RENDERER_CONFIG IMGUI_OGL3
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# define RENDERER(x) ((RENDERER_PRIV_##x()) == CONCAT(RENDERER_PRIV_, EXPAND(RENDERER_CONFIG))() && (RENDERER_HAVE_##x()))
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
#define IDI_APPLICATION 32512
|
||||
|
||||
IDI_APPLICATION ICON "${ApplicationIcon}"
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
add_example_executable(basic-interaction-example
|
||||
basic-interaction-example.cpp
|
||||
)
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
# include <imgui.h>
|
||||
# include <imgui_node_editor.h>
|
||||
# include <application.h>
|
||||
|
||||
namespace ed = ax::NodeEditor;
|
||||
|
||||
struct Example:
|
||||
public Application
|
||||
{
|
||||
// Struct to hold basic information about connection between
|
||||
// pins. Note that connection (aka. link) has its own ID.
|
||||
// This is useful later with dealing with selections, deletion
|
||||
// or other operations.
|
||||
struct LinkInfo
|
||||
{
|
||||
ed::LinkId Id;
|
||||
ed::PinId InputId;
|
||||
ed::PinId OutputId;
|
||||
};
|
||||
|
||||
using Application::Application;
|
||||
|
||||
void OnStart() override
|
||||
{
|
||||
ed::Config config;
|
||||
config.SettingsFile = "BasicInteraction.json";
|
||||
m_Context = ed::CreateEditor(&config);
|
||||
}
|
||||
|
||||
void OnStop() override
|
||||
{
|
||||
ed::DestroyEditor(m_Context);
|
||||
}
|
||||
|
||||
void ImGuiEx_BeginColumn()
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
}
|
||||
|
||||
void ImGuiEx_NextColumn()
|
||||
{
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
}
|
||||
|
||||
void ImGuiEx_EndColumn()
|
||||
{
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
void OnFrame(float deltaTime) override
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ed::SetCurrentEditor(m_Context);
|
||||
|
||||
// Start interaction with editor.
|
||||
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||
|
||||
int uniqueId = 1;
|
||||
|
||||
//
|
||||
// 1) Commit known data to editor
|
||||
//
|
||||
|
||||
// Submit Node A
|
||||
ed::NodeId nodeA_Id = uniqueId++;
|
||||
ed::PinId nodeA_InputPinId = uniqueId++;
|
||||
ed::PinId nodeA_OutputPinId = uniqueId++;
|
||||
|
||||
if (m_FirstFrame)
|
||||
ed::SetNodePosition(nodeA_Id, ImVec2(10, 10));
|
||||
ed::BeginNode(nodeA_Id);
|
||||
ImGui::Text("Node A");
|
||||
ed::BeginPin(nodeA_InputPinId, ed::PinKind::Input);
|
||||
ImGui::Text("-> In");
|
||||
ed::EndPin();
|
||||
ImGui::SameLine();
|
||||
ed::BeginPin(nodeA_OutputPinId, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
ed::EndNode();
|
||||
|
||||
// Submit Node B
|
||||
ed::NodeId nodeB_Id = uniqueId++;
|
||||
ed::PinId nodeB_InputPinId1 = uniqueId++;
|
||||
ed::PinId nodeB_InputPinId2 = uniqueId++;
|
||||
ed::PinId nodeB_OutputPinId = uniqueId++;
|
||||
|
||||
if (m_FirstFrame)
|
||||
ed::SetNodePosition(nodeB_Id, ImVec2(210, 60));
|
||||
ed::BeginNode(nodeB_Id);
|
||||
ImGui::Text("Node B");
|
||||
ImGuiEx_BeginColumn();
|
||||
ed::BeginPin(nodeB_InputPinId1, ed::PinKind::Input);
|
||||
ImGui::Text("-> In1");
|
||||
ed::EndPin();
|
||||
ed::BeginPin(nodeB_InputPinId2, ed::PinKind::Input);
|
||||
ImGui::Text("-> In2");
|
||||
ed::EndPin();
|
||||
ImGuiEx_NextColumn();
|
||||
ed::BeginPin(nodeB_OutputPinId, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
ImGuiEx_EndColumn();
|
||||
ed::EndNode();
|
||||
|
||||
// Submit Links
|
||||
for (auto& linkInfo : m_Links)
|
||||
ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId);
|
||||
|
||||
//
|
||||
// 2) Handle interactions
|
||||
//
|
||||
|
||||
// Handle creation action, returns true if editor want to create new object (node or link)
|
||||
if (ed::BeginCreate())
|
||||
{
|
||||
ed::PinId inputPinId, outputPinId;
|
||||
if (ed::QueryNewLink(&inputPinId, &outputPinId))
|
||||
{
|
||||
// QueryNewLink returns true if editor want to create new link between pins.
|
||||
//
|
||||
// Link can be created only for two valid pins, it is up to you to
|
||||
// validate if connection make sense. Editor is happy to make any.
|
||||
//
|
||||
// Link always goes from input to output. User may choose to drag
|
||||
// link from output pin or input pin. This determine which pin ids
|
||||
// are valid and which are not:
|
||||
// * input valid, output invalid - user started to drag new ling from input pin
|
||||
// * input invalid, output valid - user started to drag new ling from output pin
|
||||
// * input valid, output valid - user dragged link over other pin, can be validated
|
||||
|
||||
if (inputPinId && outputPinId) // both are valid, let's accept link
|
||||
{
|
||||
// ed::AcceptNewItem() return true when user release mouse button.
|
||||
if (ed::AcceptNewItem())
|
||||
{
|
||||
// Since we accepted new link, lets add one to our list of links.
|
||||
m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId });
|
||||
|
||||
// Draw new link.
|
||||
ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId);
|
||||
}
|
||||
|
||||
// You may choose to reject connection between these nodes
|
||||
// by calling ed::RejectNewItem(). This will allow editor to give
|
||||
// visual feedback by changing link thickness and color.
|
||||
}
|
||||
}
|
||||
}
|
||||
ed::EndCreate(); // Wraps up object creation action handling.
|
||||
|
||||
|
||||
// Handle deletion action
|
||||
if (ed::BeginDelete())
|
||||
{
|
||||
// There may be many links marked for deletion, let's loop over them.
|
||||
ed::LinkId deletedLinkId;
|
||||
while (ed::QueryDeletedLink(&deletedLinkId))
|
||||
{
|
||||
// If you agree that link can be deleted, accept deletion.
|
||||
if (ed::AcceptDeletedItem())
|
||||
{
|
||||
// Then remove link from your data.
|
||||
for (auto& link : m_Links)
|
||||
{
|
||||
if (link.Id == deletedLinkId)
|
||||
{
|
||||
m_Links.erase(&link);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// You may reject link deletion by calling:
|
||||
// ed::RejectDeletedItem();
|
||||
}
|
||||
}
|
||||
ed::EndDelete(); // Wrap up deletion action
|
||||
|
||||
|
||||
|
||||
// End of interaction with editor.
|
||||
ed::End();
|
||||
|
||||
if (m_FirstFrame)
|
||||
ed::NavigateToContent(0.0f);
|
||||
|
||||
ed::SetCurrentEditor(nullptr);
|
||||
|
||||
m_FirstFrame = false;
|
||||
|
||||
// ImGui::ShowMetricsWindow();
|
||||
}
|
||||
|
||||
ed::EditorContext* m_Context = nullptr; // Editor context, required to trace a editor state.
|
||||
bool m_FirstFrame = true; // Flag set for first frame only, some action need to be executed once.
|
||||
ImVector<LinkInfo> m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
||||
int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure.
|
||||
};
|
||||
|
||||
int Main(int argc, char** argv)
|
||||
{
|
||||
Example exampe("Basic Interaction", argc, argv);
|
||||
|
||||
if (exampe.Create())
|
||||
return exampe.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
add_example_executable(blueprints-example
|
||||
blueprints-example.cpp
|
||||
utilities/builders.h
|
||||
utilities/drawing.h
|
||||
utilities/widgets.h
|
||||
utilities/builders.cpp
|
||||
utilities/drawing.cpp
|
||||
utilities/widgets.cpp
|
||||
)
|
||||
Vendored
+1823
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 332 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 168 B |
Vendored
+310
@@ -0,0 +1,310 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// LICENSE
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// CREDITS
|
||||
// Written by Michal Cichon
|
||||
//------------------------------------------------------------------------------
|
||||
# include "builders.h"
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include <imgui_internal.h>
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
namespace ed = ax::NodeEditor;
|
||||
namespace util = ax::NodeEditor::Utilities;
|
||||
|
||||
util::BlueprintNodeBuilder::BlueprintNodeBuilder(ImTextureID texture, int textureWidth, int textureHeight):
|
||||
HeaderTextureId(texture),
|
||||
HeaderTextureWidth(textureWidth),
|
||||
HeaderTextureHeight(textureHeight),
|
||||
CurrentNodeId(0),
|
||||
CurrentStage(Stage::Invalid),
|
||||
HasHeader(false)
|
||||
{
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::Begin(ed::NodeId id)
|
||||
{
|
||||
HasHeader = false;
|
||||
HeaderMin = HeaderMax = ImVec2();
|
||||
|
||||
ed::PushStyleVar(StyleVar_NodePadding, ImVec4(8, 4, 8, 8));
|
||||
|
||||
ed::BeginNode(id);
|
||||
|
||||
ImGui::PushID(id.AsPointer());
|
||||
CurrentNodeId = id;
|
||||
|
||||
SetStage(Stage::Begin);
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::End()
|
||||
{
|
||||
SetStage(Stage::End);
|
||||
|
||||
ed::EndNode();
|
||||
|
||||
if (ImGui::IsItemVisible())
|
||||
{
|
||||
auto alpha = static_cast<int>(255 * ImGui::GetStyle().Alpha);
|
||||
|
||||
auto drawList = ed::GetNodeBackgroundDrawList(CurrentNodeId);
|
||||
|
||||
const auto halfBorderWidth = ed::GetStyle().NodeBorderWidth * 0.5f;
|
||||
|
||||
auto headerColor = IM_COL32(0, 0, 0, alpha) | (HeaderColor & IM_COL32(255, 255, 255, 0));
|
||||
if ((HeaderMax.x > HeaderMin.x) && (HeaderMax.y > HeaderMin.y) && HeaderTextureId)
|
||||
{
|
||||
const auto uv = ImVec2(
|
||||
(HeaderMax.x - HeaderMin.x) / (float)(4.0f * HeaderTextureWidth),
|
||||
(HeaderMax.y - HeaderMin.y) / (float)(4.0f * HeaderTextureHeight));
|
||||
|
||||
drawList->AddImageRounded(HeaderTextureId,
|
||||
HeaderMin - ImVec2(8 - halfBorderWidth, 4 - halfBorderWidth),
|
||||
HeaderMax + ImVec2(8 - halfBorderWidth, 0),
|
||||
ImVec2(0.0f, 0.0f), uv,
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
headerColor, GetStyle().NodeRounding, ImDrawFlags_RoundCornersTop);
|
||||
#else
|
||||
headerColor, GetStyle().NodeRounding, 1 | 2);
|
||||
#endif
|
||||
|
||||
if (ContentMin.y > HeaderMax.y)
|
||||
{
|
||||
drawList->AddLine(
|
||||
ImVec2(HeaderMin.x - (8 - halfBorderWidth), HeaderMax.y - 0.5f),
|
||||
ImVec2(HeaderMax.x + (8 - halfBorderWidth), HeaderMax.y - 0.5f),
|
||||
ImColor(255, 255, 255, 96 * alpha / (3 * 255)), 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurrentNodeId = 0;
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
ed::PopStyleVar();
|
||||
|
||||
SetStage(Stage::Invalid);
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::Header(const ImVec4& color)
|
||||
{
|
||||
HeaderColor = ImColor(color);
|
||||
SetStage(Stage::Header);
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::EndHeader()
|
||||
{
|
||||
SetStage(Stage::Content);
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::Input(ed::PinId id)
|
||||
{
|
||||
if (CurrentStage == Stage::Begin)
|
||||
SetStage(Stage::Content);
|
||||
|
||||
const auto applyPadding = (CurrentStage == Stage::Input);
|
||||
|
||||
SetStage(Stage::Input);
|
||||
|
||||
if (applyPadding)
|
||||
ImGui::Spring(0);
|
||||
|
||||
Pin(id, PinKind::Input);
|
||||
|
||||
ImGui::BeginHorizontal(id.AsPointer());
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::EndInput()
|
||||
{
|
||||
ImGui::EndHorizontal();
|
||||
|
||||
EndPin();
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::Middle()
|
||||
{
|
||||
if (CurrentStage == Stage::Begin)
|
||||
SetStage(Stage::Content);
|
||||
|
||||
SetStage(Stage::Middle);
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::Output(ed::PinId id)
|
||||
{
|
||||
if (CurrentStage == Stage::Begin)
|
||||
SetStage(Stage::Content);
|
||||
|
||||
const auto applyPadding = (CurrentStage == Stage::Output);
|
||||
|
||||
SetStage(Stage::Output);
|
||||
|
||||
if (applyPadding)
|
||||
ImGui::Spring(0);
|
||||
|
||||
Pin(id, PinKind::Output);
|
||||
|
||||
ImGui::BeginHorizontal(id.AsPointer());
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::EndOutput()
|
||||
{
|
||||
ImGui::EndHorizontal();
|
||||
|
||||
EndPin();
|
||||
}
|
||||
|
||||
bool util::BlueprintNodeBuilder::SetStage(Stage stage)
|
||||
{
|
||||
if (stage == CurrentStage)
|
||||
return false;
|
||||
|
||||
auto oldStage = CurrentStage;
|
||||
CurrentStage = stage;
|
||||
|
||||
ImVec2 cursor;
|
||||
switch (oldStage)
|
||||
{
|
||||
case Stage::Begin:
|
||||
break;
|
||||
|
||||
case Stage::Header:
|
||||
ImGui::EndHorizontal();
|
||||
HeaderMin = ImGui::GetItemRectMin();
|
||||
HeaderMax = ImGui::GetItemRectMax();
|
||||
|
||||
// spacing between header and content
|
||||
ImGui::Spring(0, ImGui::GetStyle().ItemSpacing.y * 2.0f);
|
||||
|
||||
break;
|
||||
|
||||
case Stage::Content:
|
||||
break;
|
||||
|
||||
case Stage::Input:
|
||||
ed::PopStyleVar(2);
|
||||
|
||||
ImGui::Spring(1, 0);
|
||||
ImGui::EndVertical();
|
||||
|
||||
// #debug
|
||||
// ImGui::GetWindowDrawList()->AddRect(
|
||||
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255));
|
||||
|
||||
break;
|
||||
|
||||
case Stage::Middle:
|
||||
ImGui::EndVertical();
|
||||
|
||||
// #debug
|
||||
// ImGui::GetWindowDrawList()->AddRect(
|
||||
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255));
|
||||
|
||||
break;
|
||||
|
||||
case Stage::Output:
|
||||
ed::PopStyleVar(2);
|
||||
|
||||
ImGui::Spring(1, 0);
|
||||
ImGui::EndVertical();
|
||||
|
||||
// #debug
|
||||
// ImGui::GetWindowDrawList()->AddRect(
|
||||
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 255));
|
||||
|
||||
break;
|
||||
|
||||
case Stage::End:
|
||||
break;
|
||||
|
||||
case Stage::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
case Stage::Begin:
|
||||
ImGui::BeginVertical("node");
|
||||
break;
|
||||
|
||||
case Stage::Header:
|
||||
HasHeader = true;
|
||||
|
||||
ImGui::BeginHorizontal("header");
|
||||
break;
|
||||
|
||||
case Stage::Content:
|
||||
if (oldStage == Stage::Begin)
|
||||
ImGui::Spring(0);
|
||||
|
||||
ImGui::BeginHorizontal("content");
|
||||
ImGui::Spring(0, 0);
|
||||
break;
|
||||
|
||||
case Stage::Input:
|
||||
ImGui::BeginVertical("inputs", ImVec2(0, 0), 0.0f);
|
||||
|
||||
ed::PushStyleVar(ed::StyleVar_PivotAlignment, ImVec2(0, 0.5f));
|
||||
ed::PushStyleVar(ed::StyleVar_PivotSize, ImVec2(0, 0));
|
||||
|
||||
if (!HasHeader)
|
||||
ImGui::Spring(1, 0);
|
||||
break;
|
||||
|
||||
case Stage::Middle:
|
||||
ImGui::Spring(1);
|
||||
ImGui::BeginVertical("middle", ImVec2(0, 0), 1.0f);
|
||||
break;
|
||||
|
||||
case Stage::Output:
|
||||
if (oldStage == Stage::Middle || oldStage == Stage::Input)
|
||||
ImGui::Spring(1);
|
||||
else
|
||||
ImGui::Spring(1, 0);
|
||||
ImGui::BeginVertical("outputs", ImVec2(0, 0), 1.0f);
|
||||
|
||||
ed::PushStyleVar(ed::StyleVar_PivotAlignment, ImVec2(1.0f, 0.5f));
|
||||
ed::PushStyleVar(ed::StyleVar_PivotSize, ImVec2(0, 0));
|
||||
|
||||
if (!HasHeader)
|
||||
ImGui::Spring(1, 0);
|
||||
break;
|
||||
|
||||
case Stage::End:
|
||||
if (oldStage == Stage::Input)
|
||||
ImGui::Spring(1, 0);
|
||||
if (oldStage != Stage::Begin)
|
||||
ImGui::EndHorizontal();
|
||||
ContentMin = ImGui::GetItemRectMin();
|
||||
ContentMax = ImGui::GetItemRectMax();
|
||||
|
||||
//ImGui::Spring(0);
|
||||
ImGui::EndVertical();
|
||||
NodeMin = ImGui::GetItemRectMin();
|
||||
NodeMax = ImGui::GetItemRectMax();
|
||||
break;
|
||||
|
||||
case Stage::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::Pin(ed::PinId id, ed::PinKind kind)
|
||||
{
|
||||
ed::BeginPin(id, kind);
|
||||
}
|
||||
|
||||
void util::BlueprintNodeBuilder::EndPin()
|
||||
{
|
||||
ed::EndPin();
|
||||
|
||||
// #debug
|
||||
// ImGui::GetWindowDrawList()->AddRectFilled(
|
||||
// ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 0, 0, 64));
|
||||
}
|
||||
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// LICENSE
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
//
|
||||
// CREDITS
|
||||
// Written by Michal Cichon
|
||||
//------------------------------------------------------------------------------
|
||||
# pragma once
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
# include <imgui_node_editor.h>
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
namespace ax {
|
||||
namespace NodeEditor {
|
||||
namespace Utilities {
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
struct BlueprintNodeBuilder
|
||||
{
|
||||
BlueprintNodeBuilder(ImTextureID texture = nullptr, int textureWidth = 0, int textureHeight = 0);
|
||||
|
||||
void Begin(NodeId id);
|
||||
void End();
|
||||
|
||||
void Header(const ImVec4& color = ImVec4(1, 1, 1, 1));
|
||||
void EndHeader();
|
||||
|
||||
void Input(PinId id);
|
||||
void EndInput();
|
||||
|
||||
void Middle();
|
||||
|
||||
void Output(PinId id);
|
||||
void EndOutput();
|
||||
|
||||
|
||||
private:
|
||||
enum class Stage
|
||||
{
|
||||
Invalid,
|
||||
Begin,
|
||||
Header,
|
||||
Content,
|
||||
Input,
|
||||
Output,
|
||||
Middle,
|
||||
End
|
||||
};
|
||||
|
||||
bool SetStage(Stage stage);
|
||||
|
||||
void Pin(PinId id, ax::NodeEditor::PinKind kind);
|
||||
void EndPin();
|
||||
|
||||
ImTextureID HeaderTextureId;
|
||||
int HeaderTextureWidth;
|
||||
int HeaderTextureHeight;
|
||||
NodeId CurrentNodeId;
|
||||
Stage CurrentStage;
|
||||
ImU32 HeaderColor;
|
||||
ImVec2 NodeMin;
|
||||
ImVec2 NodeMax;
|
||||
ImVec2 HeaderMin;
|
||||
ImVec2 HeaderMax;
|
||||
ImVec2 ContentMin;
|
||||
ImVec2 ContentMax;
|
||||
bool HasHeader;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
} // namespace Utilities
|
||||
} // namespace Editor
|
||||
} // namespace ax
|
||||
Vendored
+252
@@ -0,0 +1,252 @@
|
||||
# include "drawing.h"
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include <imgui_internal.h>
|
||||
|
||||
void ax::Drawing::DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor)
|
||||
{
|
||||
auto rect = ImRect(a, b);
|
||||
auto rect_x = rect.Min.x;
|
||||
auto rect_y = rect.Min.y;
|
||||
auto rect_w = rect.Max.x - rect.Min.x;
|
||||
auto rect_h = rect.Max.y - rect.Min.y;
|
||||
auto rect_center_x = (rect.Min.x + rect.Max.x) * 0.5f;
|
||||
auto rect_center_y = (rect.Min.y + rect.Max.y) * 0.5f;
|
||||
auto rect_center = ImVec2(rect_center_x, rect_center_y);
|
||||
const auto outline_scale = rect_w / 24.0f;
|
||||
const auto extra_segments = static_cast<int>(2 * outline_scale); // for full circle
|
||||
|
||||
if (type == IconType::Flow)
|
||||
{
|
||||
const auto origin_scale = rect_w / 24.0f;
|
||||
|
||||
const auto offset_x = 1.0f * origin_scale;
|
||||
const auto offset_y = 0.0f * origin_scale;
|
||||
const auto margin = (filled ? 2.0f : 2.0f) * origin_scale;
|
||||
const auto rounding = 0.1f * origin_scale;
|
||||
const auto tip_round = 0.7f; // percentage of triangle edge (for tip)
|
||||
//const auto edge_round = 0.7f; // percentage of triangle edge (for corner)
|
||||
const auto canvas = ImRect(
|
||||
rect.Min.x + margin + offset_x,
|
||||
rect.Min.y + margin + offset_y,
|
||||
rect.Max.x - margin + offset_x,
|
||||
rect.Max.y - margin + offset_y);
|
||||
const auto canvas_x = canvas.Min.x;
|
||||
const auto canvas_y = canvas.Min.y;
|
||||
const auto canvas_w = canvas.Max.x - canvas.Min.x;
|
||||
const auto canvas_h = canvas.Max.y - canvas.Min.y;
|
||||
|
||||
const auto left = canvas_x + canvas_w * 0.5f * 0.3f;
|
||||
const auto right = canvas_x + canvas_w - canvas_w * 0.5f * 0.3f;
|
||||
const auto top = canvas_y + canvas_h * 0.5f * 0.2f;
|
||||
const auto bottom = canvas_y + canvas_h - canvas_h * 0.5f * 0.2f;
|
||||
const auto center_y = (top + bottom) * 0.5f;
|
||||
//const auto angle = AX_PI * 0.5f * 0.5f * 0.5f;
|
||||
|
||||
const auto tip_top = ImVec2(canvas_x + canvas_w * 0.5f, top);
|
||||
const auto tip_right = ImVec2(right, center_y);
|
||||
const auto tip_bottom = ImVec2(canvas_x + canvas_w * 0.5f, bottom);
|
||||
|
||||
drawList->PathLineTo(ImVec2(left, top) + ImVec2(0, rounding));
|
||||
drawList->PathBezierCubicCurveTo(
|
||||
ImVec2(left, top),
|
||||
ImVec2(left, top),
|
||||
ImVec2(left, top) + ImVec2(rounding, 0));
|
||||
drawList->PathLineTo(tip_top);
|
||||
drawList->PathLineTo(tip_top + (tip_right - tip_top) * tip_round);
|
||||
drawList->PathBezierCubicCurveTo(
|
||||
tip_right,
|
||||
tip_right,
|
||||
tip_bottom + (tip_right - tip_bottom) * tip_round);
|
||||
drawList->PathLineTo(tip_bottom);
|
||||
drawList->PathLineTo(ImVec2(left, bottom) + ImVec2(rounding, 0));
|
||||
drawList->PathBezierCubicCurveTo(
|
||||
ImVec2(left, bottom),
|
||||
ImVec2(left, bottom),
|
||||
ImVec2(left, bottom) - ImVec2(0, rounding));
|
||||
|
||||
if (!filled)
|
||||
{
|
||||
if (innerColor & 0xFF000000)
|
||||
drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor);
|
||||
|
||||
drawList->PathStroke(color, true, 2.0f * outline_scale);
|
||||
}
|
||||
else
|
||||
drawList->PathFillConvex(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto triangleStart = rect_center_x + 0.32f * rect_w;
|
||||
|
||||
auto rect_offset = -static_cast<int>(rect_w * 0.25f * 0.25f);
|
||||
|
||||
rect.Min.x += rect_offset;
|
||||
rect.Max.x += rect_offset;
|
||||
rect_x += rect_offset;
|
||||
rect_center_x += rect_offset * 0.5f;
|
||||
rect_center.x += rect_offset * 0.5f;
|
||||
|
||||
if (type == IconType::Circle)
|
||||
{
|
||||
const auto c = rect_center;
|
||||
|
||||
if (!filled)
|
||||
{
|
||||
const auto r = 0.5f * rect_w / 2.0f - 0.5f;
|
||||
|
||||
if (innerColor & 0xFF000000)
|
||||
drawList->AddCircleFilled(c, r, innerColor, 12 + extra_segments);
|
||||
drawList->AddCircle(c, r, color, 12 + extra_segments, 2.0f * outline_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawList->AddCircleFilled(c, 0.5f * rect_w / 2.0f, color, 12 + extra_segments);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == IconType::Square)
|
||||
{
|
||||
if (filled)
|
||||
{
|
||||
const auto r = 0.5f * rect_w / 2.0f;
|
||||
const auto p0 = rect_center - ImVec2(r, r);
|
||||
const auto p1 = rect_center + ImVec2(r, r);
|
||||
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
drawList->AddRectFilled(p0, p1, color, 0, ImDrawFlags_RoundCornersAll);
|
||||
#else
|
||||
drawList->AddRectFilled(p0, p1, color, 0, 15);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto r = 0.5f * rect_w / 2.0f - 0.5f;
|
||||
const auto p0 = rect_center - ImVec2(r, r);
|
||||
const auto p1 = rect_center + ImVec2(r, r);
|
||||
|
||||
if (innerColor & 0xFF000000)
|
||||
{
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
drawList->AddRectFilled(p0, p1, innerColor, 0, ImDrawFlags_RoundCornersAll);
|
||||
#else
|
||||
drawList->AddRectFilled(p0, p1, innerColor, 0, 15);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
drawList->AddRect(p0, p1, color, 0, ImDrawFlags_RoundCornersAll, 2.0f * outline_scale);
|
||||
#else
|
||||
drawList->AddRect(p0, p1, color, 0, 15, 2.0f * outline_scale);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (type == IconType::Grid)
|
||||
{
|
||||
const auto r = 0.5f * rect_w / 2.0f;
|
||||
const auto w = ceilf(r / 3.0f);
|
||||
|
||||
const auto baseTl = ImVec2(floorf(rect_center_x - w * 2.5f), floorf(rect_center_y - w * 2.5f));
|
||||
const auto baseBr = ImVec2(floorf(baseTl.x + w), floorf(baseTl.y + w));
|
||||
|
||||
auto tl = baseTl;
|
||||
auto br = baseBr;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
tl.x = baseTl.x;
|
||||
br.x = baseBr.x;
|
||||
drawList->AddRectFilled(tl, br, color);
|
||||
tl.x += w * 2;
|
||||
br.x += w * 2;
|
||||
if (i != 1 || filled)
|
||||
drawList->AddRectFilled(tl, br, color);
|
||||
tl.x += w * 2;
|
||||
br.x += w * 2;
|
||||
drawList->AddRectFilled(tl, br, color);
|
||||
|
||||
tl.y += w * 2;
|
||||
br.y += w * 2;
|
||||
}
|
||||
|
||||
triangleStart = br.x + w + 1.0f / 24.0f * rect_w;
|
||||
}
|
||||
|
||||
if (type == IconType::RoundSquare)
|
||||
{
|
||||
if (filled)
|
||||
{
|
||||
const auto r = 0.5f * rect_w / 2.0f;
|
||||
const auto cr = r * 0.5f;
|
||||
const auto p0 = rect_center - ImVec2(r, r);
|
||||
const auto p1 = rect_center + ImVec2(r, r);
|
||||
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
drawList->AddRectFilled(p0, p1, color, cr, ImDrawFlags_RoundCornersAll);
|
||||
#else
|
||||
drawList->AddRectFilled(p0, p1, color, cr, 15);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto r = 0.5f * rect_w / 2.0f - 0.5f;
|
||||
const auto cr = r * 0.5f;
|
||||
const auto p0 = rect_center - ImVec2(r, r);
|
||||
const auto p1 = rect_center + ImVec2(r, r);
|
||||
|
||||
if (innerColor & 0xFF000000)
|
||||
{
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
drawList->AddRectFilled(p0, p1, innerColor, cr, ImDrawFlags_RoundCornersAll);
|
||||
#else
|
||||
drawList->AddRectFilled(p0, p1, innerColor, cr, 15);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if IMGUI_VERSION_NUM > 18101
|
||||
drawList->AddRect(p0, p1, color, cr, ImDrawFlags_RoundCornersAll, 2.0f * outline_scale);
|
||||
#else
|
||||
drawList->AddRect(p0, p1, color, cr, 15, 2.0f * outline_scale);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (type == IconType::Diamond)
|
||||
{
|
||||
if (filled)
|
||||
{
|
||||
const auto r = 0.607f * rect_w / 2.0f;
|
||||
const auto c = rect_center;
|
||||
|
||||
drawList->PathLineTo(c + ImVec2( 0, -r));
|
||||
drawList->PathLineTo(c + ImVec2( r, 0));
|
||||
drawList->PathLineTo(c + ImVec2( 0, r));
|
||||
drawList->PathLineTo(c + ImVec2(-r, 0));
|
||||
drawList->PathFillConvex(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto r = 0.607f * rect_w / 2.0f - 0.5f;
|
||||
const auto c = rect_center;
|
||||
|
||||
drawList->PathLineTo(c + ImVec2( 0, -r));
|
||||
drawList->PathLineTo(c + ImVec2( r, 0));
|
||||
drawList->PathLineTo(c + ImVec2( 0, r));
|
||||
drawList->PathLineTo(c + ImVec2(-r, 0));
|
||||
|
||||
if (innerColor & 0xFF000000)
|
||||
drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor);
|
||||
|
||||
drawList->PathStroke(color, true, 2.0f * outline_scale);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto triangleTip = triangleStart + rect_w * (0.45f - 0.32f);
|
||||
|
||||
drawList->AddTriangleFilled(
|
||||
ImVec2(ceilf(triangleTip), rect_y + rect_h * 0.5f),
|
||||
ImVec2(triangleStart, rect_center_y + 0.15f * rect_h),
|
||||
ImVec2(triangleStart, rect_center_y - 0.15f * rect_h),
|
||||
color);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
# pragma once
|
||||
# include <imgui.h>
|
||||
|
||||
namespace ax {
|
||||
namespace Drawing {
|
||||
|
||||
enum class IconType: ImU32 { Flow, Circle, Square, Grid, RoundSquare, Diamond };
|
||||
|
||||
void DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor);
|
||||
|
||||
} // namespace Drawing
|
||||
} // namespace ax
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
# include "widgets.h"
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include <imgui_internal.h>
|
||||
|
||||
void ax::Widgets::Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color/* = ImVec4(1, 1, 1, 1)*/, const ImVec4& innerColor/* = ImVec4(0, 0, 0, 0)*/)
|
||||
{
|
||||
if (ImGui::IsRectVisible(size))
|
||||
{
|
||||
auto cursorPos = ImGui::GetCursorScreenPos();
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
ax::Drawing::DrawIcon(drawList, cursorPos, cursorPos + size, type, filled, ImColor(color), ImColor(innerColor));
|
||||
}
|
||||
|
||||
ImGui::Dummy(size);
|
||||
}
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <imgui.h>
|
||||
#include "drawing.h"
|
||||
|
||||
namespace ax {
|
||||
namespace Widgets {
|
||||
|
||||
using Drawing::IconType;
|
||||
|
||||
void Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color = ImVec4(1, 1, 1, 1), const ImVec4& innerColor = ImVec4(0, 0, 0, 0));
|
||||
|
||||
} // namespace Widgets
|
||||
} // namespace ax
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
add_example_executable(canvas-example
|
||||
canvas-example.cpp
|
||||
)
|
||||
|
||||
#target_link_libraries(Canvas PRIVATE imgui_canvas)
|
||||
Vendored
+251
@@ -0,0 +1,251 @@
|
||||
# include <imgui.h>
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include <imgui_internal.h>
|
||||
# include <imgui_canvas.h>
|
||||
# include <application.h>
|
||||
|
||||
static void DrawScale(const ImVec2& from, const ImVec2& to, float majorUnit, float minorUnit, float labelAlignment, float sign = 1.0f)
|
||||
{
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
auto direction = (to - from) * ImInvLength(to - from, 0.0f);
|
||||
auto normal = ImVec2(-direction.y, direction.x);
|
||||
auto distance = sqrtf(ImLengthSqr(to - from));
|
||||
|
||||
if (ImDot(direction, direction) < FLT_EPSILON)
|
||||
return;
|
||||
|
||||
auto minorSize = 5.0f;
|
||||
auto majorSize = 10.0f;
|
||||
auto labelDistance = 8.0f;
|
||||
|
||||
drawList->AddLine(from, to, IM_COL32(255, 255, 255, 255));
|
||||
|
||||
auto p = from;
|
||||
for (auto d = 0.0f; d <= distance; d += minorUnit, p += direction * minorUnit)
|
||||
drawList->AddLine(p - normal * minorSize, p + normal * minorSize, IM_COL32(255, 255, 255, 255));
|
||||
|
||||
for (auto d = 0.0f; d <= distance + majorUnit; d += majorUnit)
|
||||
{
|
||||
p = from + direction * d;
|
||||
|
||||
drawList->AddLine(p - normal * majorSize, p + normal * majorSize, IM_COL32(255, 255, 255, 255));
|
||||
|
||||
if (d == 0.0f)
|
||||
continue;
|
||||
|
||||
char label[16];
|
||||
snprintf(label, 15, "%g", d * sign);
|
||||
auto labelSize = ImGui::CalcTextSize(label);
|
||||
|
||||
auto labelPosition = p + ImVec2(fabsf(normal.x), fabsf(normal.y)) * labelDistance;
|
||||
auto labelAlignedSize = ImDot(labelSize, direction);
|
||||
labelPosition += direction * (-labelAlignedSize + labelAlignment * labelAlignedSize * 2.0f);
|
||||
labelPosition = ImFloor(labelPosition + ImVec2(0.5f, 0.5f));
|
||||
|
||||
drawList->AddText(labelPosition, IM_COL32(255, 255, 255, 255), label);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f)
|
||||
{
|
||||
using namespace ImGui;
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
ImGuiID id = window->GetID("##Splitter");
|
||||
ImRect bb;
|
||||
bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
|
||||
bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f);
|
||||
return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f);
|
||||
}
|
||||
|
||||
struct Example:
|
||||
public Application
|
||||
{
|
||||
using Application::Application;
|
||||
|
||||
void OnFrame(float deltaTime) override
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
auto availableRegion = ImGui::GetContentRegionAvail();
|
||||
|
||||
static float s_SplitterSize = 6.0f;
|
||||
static float s_SplitterArea = 0.0f;
|
||||
static float s_LeftPaneSize = 0.0f;
|
||||
static float s_RightPaneSize = 0.0f;
|
||||
|
||||
if (s_SplitterArea != availableRegion.x)
|
||||
{
|
||||
if (s_SplitterArea == 0.0f)
|
||||
{
|
||||
s_SplitterArea = availableRegion.x;
|
||||
s_LeftPaneSize = ImFloor(availableRegion.x * 0.25f);
|
||||
s_RightPaneSize = availableRegion.x - s_LeftPaneSize - s_SplitterSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ratio = availableRegion.x / s_SplitterArea;
|
||||
s_SplitterArea = availableRegion.x;
|
||||
s_LeftPaneSize = s_LeftPaneSize * ratio;
|
||||
s_RightPaneSize = availableRegion.x - s_LeftPaneSize - s_SplitterSize;
|
||||
}
|
||||
}
|
||||
|
||||
static ImGuiEx::Canvas canvas;
|
||||
static ImVec2 drawStartPoint;
|
||||
static bool isDragging = false;
|
||||
static ImRect panelRect;
|
||||
|
||||
Splitter(true, s_SplitterSize, &s_LeftPaneSize, &s_RightPaneSize, 100.0f, 100.0f);
|
||||
|
||||
auto canvasRect = canvas.Rect();
|
||||
auto viewRect = canvas.ViewRect();
|
||||
auto viewOrigin = canvas.ViewOrigin();
|
||||
auto viewScale = canvas.ViewScale();
|
||||
|
||||
ImGui::BeginChild("##top", ImVec2(s_LeftPaneSize, -1), false, ImGuiWindowFlags_NoScrollWithMouse);
|
||||
|
||||
ImGui::TextUnformatted("Rect:");
|
||||
ImGui::BeginColumns("rect", 2, ImGuiOldColumnFlags_NoBorder);
|
||||
ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x);
|
||||
ImGui::Text("\tL: %.2f", canvasRect.Min.x); ImGui::NextColumn();
|
||||
ImGui::Text("\tT: %.2f", canvasRect.Min.y); ImGui::NextColumn();
|
||||
ImGui::Text("\tR: %.2f", canvasRect.Max.x); ImGui::NextColumn();
|
||||
ImGui::Text("\tB: %.2f", canvasRect.Max.y); ImGui::NextColumn();
|
||||
ImGui::Text("\tW: %.2f", canvasRect.GetWidth()); ImGui::NextColumn();
|
||||
ImGui::Text("\tH: %.2f", canvasRect.GetHeight()); ImGui::NextColumn();
|
||||
ImGui::EndColumns();
|
||||
|
||||
ImGui::TextUnformatted("View Rect:");
|
||||
ImGui::BeginColumns("viewrect", 2, ImGuiOldColumnFlags_NoBorder);
|
||||
ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x);
|
||||
ImGui::Text("\tL: %.2f", viewRect.Min.x); ImGui::NextColumn();
|
||||
ImGui::Text("\tT: %.2f", viewRect.Min.y); ImGui::NextColumn();
|
||||
ImGui::Text("\tR: %.2f", viewRect.Max.x); ImGui::NextColumn();
|
||||
ImGui::Text("\tB: %.2f", viewRect.Max.y); ImGui::NextColumn();
|
||||
ImGui::Text("\tW: %.2f", viewRect.GetWidth()); ImGui::NextColumn();
|
||||
ImGui::Text("\tH: %.2f", viewRect.GetHeight()); ImGui::NextColumn();
|
||||
ImGui::EndColumns();
|
||||
|
||||
ImGui::TextUnformatted("Origin:");
|
||||
ImGui::Indent();
|
||||
auto originChanged = false;
|
||||
ImGui::PushItemWidth(-ImGui::GetStyle().IndentSpacing);
|
||||
originChanged |= ImGui::DragFloat("##originx", &viewOrigin.x, 1.0f);
|
||||
originChanged |= ImGui::DragFloat("##originy", &viewOrigin.y, 1.0f);
|
||||
if (originChanged) canvas.SetView(viewOrigin, viewScale);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Unindent();
|
||||
|
||||
ImGui::TextUnformatted("Scale:");
|
||||
ImGui::Indent();
|
||||
ImGui::PushItemWidth(-ImGui::GetStyle().IndentSpacing);
|
||||
if (ImGui::DragFloat("##scale", &viewScale, 0.01f, 0.01f, 15.0f))
|
||||
canvas.SetView(viewOrigin, viewScale);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Unindent();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("Center over Panel", ImVec2(s_LeftPaneSize, 0)))
|
||||
canvas.CenterView(panelRect.GetCenter());
|
||||
|
||||
if (ImGui::Button("Center and zoom to Panel", ImVec2(s_LeftPaneSize, 0)))
|
||||
canvas.CenterView(panelRect);
|
||||
|
||||
ImGui::TextUnformatted("Panel Rect:");
|
||||
ImGui::BeginColumns("panelrect", 2, ImGuiOldColumnFlags_NoBorder);
|
||||
ImGui::SetColumnWidth(0, ImGui::CalcTextSize("\t\tL: 0000.00\t").x);
|
||||
ImGui::Text("\tL: %.2f", panelRect.Min.x); ImGui::NextColumn();
|
||||
ImGui::Text("\tT: %.2f", panelRect.Min.y); ImGui::NextColumn();
|
||||
ImGui::Text("\tR: %.2f", panelRect.Max.x); ImGui::NextColumn();
|
||||
ImGui::Text("\tB: %.2f", panelRect.Max.y); ImGui::NextColumn();
|
||||
ImGui::Text("\tW: %.2f", panelRect.GetWidth()); ImGui::NextColumn();
|
||||
ImGui::Text("\tH: %.2f", panelRect.GetHeight()); ImGui::NextColumn();
|
||||
ImGui::EndColumns();
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine(0.0f, s_SplitterSize);
|
||||
|
||||
|
||||
if (canvas.Begin("##mycanvas", ImVec2(s_RightPaneSize, 0.0f)))
|
||||
{
|
||||
//auto drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
if ((isDragging || ImGui::IsItemHovered()) && ImGui::IsMouseDragging(1, 0.0f))
|
||||
{
|
||||
if (!isDragging)
|
||||
{
|
||||
isDragging = true;
|
||||
drawStartPoint = viewOrigin;
|
||||
}
|
||||
|
||||
canvas.SetView(drawStartPoint + ImGui::GetMouseDragDelta(1, 0.0f) * viewScale, viewScale);
|
||||
}
|
||||
else if (isDragging)
|
||||
isDragging = false;
|
||||
|
||||
viewRect = canvas.ViewRect();
|
||||
|
||||
if (viewRect.Max.x > 0.0f)
|
||||
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(viewRect.Max.x, 0.0f), 100.0f, 10.0f, 0.6f);
|
||||
if (viewRect.Min.x < 0.0f)
|
||||
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(viewRect.Min.x, 0.0f), 100.0f, 10.0f, 0.6f, -1.0f);
|
||||
if (viewRect.Max.y > 0.0f)
|
||||
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(0.0f, viewRect.Max.y), 100.0f, 10.0f, 0.6f);
|
||||
if (viewRect.Min.y < 0.0f)
|
||||
DrawScale(ImVec2(0.0f, 0.0f), ImVec2(0.0f, viewRect.Min.y), 100.0f, 10.0f, 0.6f, -1.0f);
|
||||
|
||||
ImGui::Text("Hovered: %d", ImGui::IsItemHovered() ? 1 : 0);
|
||||
|
||||
ImGui::TextUnformatted("Hello World!");
|
||||
|
||||
ImGui::Bullet();
|
||||
|
||||
ImGui::Button("Panel", ImVec2(s_RightPaneSize * 0.75f, availableRegion.y * 0.5f) * 0.5f);
|
||||
panelRect.Min = ImGui::GetItemRectMin();
|
||||
panelRect.Max = ImGui::GetItemRectMax();
|
||||
|
||||
canvas.End();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//ed::SetCurrentEditor(g_Context);
|
||||
//ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||
//int uniqueId = 1;
|
||||
//// Start drawing nodes.
|
||||
//ed::BeginNode(uniqueId++);
|
||||
// ImGui::Text("Node A");
|
||||
// ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||
// ImGui::Text("-> In");
|
||||
// ed::EndPin();
|
||||
// ImGui::SameLine();
|
||||
// ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||
// ImGui::Text("Out ->");
|
||||
// ed::EndPin();
|
||||
//ed::EndNode();
|
||||
//ed::End();
|
||||
//ed::SetCurrentEditor(nullptr);
|
||||
|
||||
//ImGui::ShowMetricsWindow();
|
||||
}
|
||||
};
|
||||
|
||||
int Main(int argc, char** argv)
|
||||
{
|
||||
Example exampe("Canvas", argc, argv);
|
||||
|
||||
if (exampe.Create())
|
||||
return exampe.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
Binary file not shown.
+93
@@ -0,0 +1,93 @@
|
||||
Copyright 2010 The Cuprum Project Authors (lemonad@jovanny.ru), with Reserved Font Name "Cuprum".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Oswald Project Authors (https://github.com/googlefonts/OswaldFont)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright (c) 2011, Jonas Hecksher, Playtypes, e-types AS (lasse@e-types.com), with Reserved Font Name 'Play', 'Playtype', 'Playtype Sans'.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
Binary file not shown.
+3
@@ -0,0 +1,3 @@
|
||||
add_example_executable(simple-example
|
||||
simple-example.cpp
|
||||
)
|
||||
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
# include <imgui.h>
|
||||
# include <imgui_node_editor.h>
|
||||
# include <application.h>
|
||||
|
||||
namespace ed = ax::NodeEditor;
|
||||
|
||||
struct Example:
|
||||
public Application
|
||||
{
|
||||
using Application::Application;
|
||||
|
||||
void OnStart() override
|
||||
{
|
||||
ed::Config config;
|
||||
config.SettingsFile = "Simple.json";
|
||||
m_Context = ed::CreateEditor(&config);
|
||||
}
|
||||
|
||||
void OnStop() override
|
||||
{
|
||||
ed::DestroyEditor(m_Context);
|
||||
}
|
||||
|
||||
void OnFrame(float deltaTime) override
|
||||
{
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ed::SetCurrentEditor(m_Context);
|
||||
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||
int uniqueId = 1;
|
||||
// Start drawing nodes.
|
||||
ed::BeginNode(uniqueId++);
|
||||
ImGui::Text("Node A");
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||
ImGui::Text("-> In");
|
||||
ed::EndPin();
|
||||
ImGui::SameLine();
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
ed::EndNode();
|
||||
ed::End();
|
||||
ed::SetCurrentEditor(nullptr);
|
||||
|
||||
//ImGui::ShowMetricsWindow();
|
||||
}
|
||||
|
||||
ed::EditorContext* m_Context = nullptr;
|
||||
};
|
||||
|
||||
int Main(int argc, char** argv)
|
||||
{
|
||||
Example exampe("Simple", argc, argv);
|
||||
|
||||
if (exampe.Create())
|
||||
return exampe.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
add_example_executable(widgets-example
|
||||
widgets-example.cpp
|
||||
)
|
||||
Vendored
+432
@@ -0,0 +1,432 @@
|
||||
// ===================================================================================================================
|
||||
// Widget Example
|
||||
// Drawing standard ImGui widgets inside the node body
|
||||
//
|
||||
// First, some unsorted notes about which widgets do and don't draw well inside nodes. Run the examples to see all the allowed widgets.
|
||||
//
|
||||
// - Child windows with scrolling doesn't work in the node. The child window appears in a normal node,
|
||||
// and scrolls, but its contents are floating around in the wrong location, and they are not scaled.
|
||||
// Note that you can put scrolling child windows into "deferred popups" (see next item).
|
||||
// - Listboxes and combo-boxes only work in nodes with a work-around: deferring the popup calls until after the node drawing is
|
||||
// completed. Look to the popup-demo for an example.
|
||||
// - Headers and trees work inside the nodes only with hacks. This is because they attempt to span the "avaialbe width"
|
||||
// and the nodes can't tell these widgets how wide it is. The work-around is to set up a fake
|
||||
// table with a static column width, then draw your header and tree widgets in that column.
|
||||
// - Clickable tabs don't work in nodes. Tabs appear, but you cannot actually change the tab, so they're functionally useless.
|
||||
// - Editable text areas work, but you have to manually manage disabling the editor shorcuts while typing is detected.
|
||||
// Look around for the call to ed::EnableShortcuts() for an example.
|
||||
// - Most of the cool graph widgets can't be used because they are hard-coded in ImGui to spawn tooltips, which don't work.
|
||||
|
||||
# include <imgui.h>
|
||||
# include <imgui_internal.h>
|
||||
# include <imgui_node_editor.h>
|
||||
# include <application.h>
|
||||
|
||||
namespace ed = ax::NodeEditor;
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# define portable_strcpy strcpy_s
|
||||
# define portable_sprintf sprintf_s
|
||||
# else
|
||||
# define portable_strcpy strcpy
|
||||
# define portable_sprintf sprintf
|
||||
# endif
|
||||
|
||||
struct Example:
|
||||
public Application
|
||||
{
|
||||
using Application::Application;
|
||||
|
||||
struct LinkInfo
|
||||
{
|
||||
ed::LinkId Id;
|
||||
ed::PinId InputId;
|
||||
ed::PinId OutputId;
|
||||
};
|
||||
|
||||
void OnStart() override
|
||||
{
|
||||
ed::Config config;
|
||||
config.SettingsFile = "Widgets.json";
|
||||
m_Context = ed::CreateEditor(&config);
|
||||
}
|
||||
|
||||
void OnStop() override
|
||||
{
|
||||
ed::DestroyEditor(m_Context);
|
||||
}
|
||||
|
||||
void OnFrame(float deltaTime) override
|
||||
{
|
||||
static bool firstframe = true; // Used to position the nodes on startup
|
||||
auto& io = ImGui::GetIO();
|
||||
|
||||
// FPS Counter Ribbon
|
||||
ImGui::Text("FPS: %.2f (%.2gms)", io.Framerate, io.Framerate ? 1000.0f / io.Framerate : 0.0f);
|
||||
ImGui::Separator();
|
||||
|
||||
// Node Editor Widget
|
||||
ed::SetCurrentEditor(m_Context);
|
||||
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
|
||||
int uniqueId = 1;
|
||||
|
||||
|
||||
// Basic Widgets Demo ==============================================================================================
|
||||
auto basic_id = uniqueId++;
|
||||
ed::BeginNode(basic_id);
|
||||
ImGui::Text("Basic Widget Demo");
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||
ImGui::Text("-> In");
|
||||
ed::EndPin();
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(250, 0)); // Hacky magic number to space out the output pin.
|
||||
ImGui::SameLine();
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
|
||||
// Widget Demo from imgui_demo.cpp...
|
||||
// Normal Button
|
||||
static int clicked = 0;
|
||||
if (ImGui::Button("Button"))
|
||||
clicked++;
|
||||
if (clicked & 1)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Thanks for clicking me!");
|
||||
}
|
||||
|
||||
// Checkbox
|
||||
static bool check = true;
|
||||
ImGui::Checkbox("checkbox", &check);
|
||||
|
||||
// Radio buttons
|
||||
static int e = 0;
|
||||
ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
|
||||
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
|
||||
ImGui::RadioButton("radio c", &e, 2);
|
||||
|
||||
// Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
ImGui::SameLine();
|
||||
ImGui::PushID(i);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f));
|
||||
ImGui::Button("Click");
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default)
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Hold to repeat:");
|
||||
ImGui::SameLine();
|
||||
|
||||
// Arrow buttons with Repeater
|
||||
static int counter = 0;
|
||||
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
|
||||
ImGui::PushButtonRepeat(true);
|
||||
if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
|
||||
ImGui::SameLine(0.0f, spacing);
|
||||
if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
|
||||
ImGui::PopButtonRepeat();
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%d", counter);
|
||||
|
||||
// The input widgets also require you to manually disable the editor shortcuts so the view doesn't fly around.
|
||||
// (note that this is a per-frame setting, so it disables it for all text boxes. I left it here so you could find it!)
|
||||
ed::EnableShortcuts(!io.WantTextInput);
|
||||
// The input widgets require some guidance on their widths, or else they're very large. (note matching pop at the end).
|
||||
ImGui::PushItemWidth(200);
|
||||
static char str1[128] = "";
|
||||
ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
|
||||
|
||||
static float f0 = 0.001f;
|
||||
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
|
||||
|
||||
static float f1 = 1.00f, f2 = 0.0067f;
|
||||
ImGui::DragFloat("drag float", &f1, 0.005f);
|
||||
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ed::EndNode();
|
||||
if (firstframe)
|
||||
{
|
||||
ed::SetNodePosition(basic_id, ImVec2(20, 20));
|
||||
}
|
||||
|
||||
// Headers and Trees Demo =======================================================================================================
|
||||
// TreeNodes and Headers streatch to the entire remaining work area. To put them in nodes what we need to do is to tell
|
||||
// ImGui out work area is shorter. We can achieve that right now only by using columns API.
|
||||
//
|
||||
// Relevent bugs: https://github.com/thedmd/imgui-node-editor/issues/30
|
||||
auto header_id = uniqueId++;
|
||||
ed::BeginNode(header_id);
|
||||
ImGui::Text("Tree Widget Demo");
|
||||
|
||||
// Pins Row
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||
ImGui::Text("-> In");
|
||||
ed::EndPin();
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(35, 0)); // magic number - Crude & simple way to nudge over the output pin. Consider using layout and springs
|
||||
ImGui::SameLine();
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
|
||||
// Tree column startup -------------------------------------------------------------------
|
||||
// Push dummy widget to extend node size. Columns do not do that.
|
||||
float width = 135; // bad magic numbers. used to define width of tree widget
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::Dummy(ImVec2(width, 0));
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
// Start columns, but use only first one.
|
||||
ImGui::BeginColumns("##TreeColumns", 2,
|
||||
ImGuiOldColumnFlags_NoBorder |
|
||||
ImGuiOldColumnFlags_NoResize |
|
||||
ImGuiOldColumnFlags_NoPreserveWidths |
|
||||
ImGuiOldColumnFlags_NoForceWithinWindow);
|
||||
|
||||
// Adjust column width to match requested one.
|
||||
ImGui::SetColumnWidth(0, width
|
||||
+ ImGui::GetStyle().WindowPadding.x
|
||||
+ ImGui::GetStyle().ItemSpacing.x);
|
||||
// End of tree column startup --------------------------------------------------------------
|
||||
|
||||
// Back to normal ImGui drawing, in our column.
|
||||
if (ImGui::CollapsingHeader("Open Header"))
|
||||
{
|
||||
ImGui::Text("Hello There");
|
||||
if (ImGui::TreeNode("Open Tree")) {
|
||||
static bool OP1_Bool = false;
|
||||
ImGui::Text("Checked: %s", OP1_Bool ? "true" : "false");
|
||||
ImGui::Checkbox("Option 1", &OP1_Bool);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
// Tree Column Shutdown
|
||||
ImGui::EndColumns();
|
||||
ed::EndNode(); // End of Tree Node Demo
|
||||
|
||||
if (firstframe)
|
||||
{
|
||||
ed::SetNodePosition(header_id, ImVec2(420, 20));
|
||||
}
|
||||
|
||||
// Tool Tip & Pop-up Demo =====================================================================================
|
||||
// Tooltips, combo-boxes, drop-down menus need to use a work-around to place the "overlay window" in the canvas.
|
||||
// To do this, we must defer the popup calls until after we're done drawing the node material.
|
||||
//
|
||||
// Relevent bugs: https://github.com/thedmd/imgui-node-editor/issues/48
|
||||
auto popup_id = uniqueId++;
|
||||
ed::BeginNode(popup_id);
|
||||
ImGui::Text("Tool Tip & Pop-up Demo");
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||
ImGui::Text("-> In");
|
||||
ed::EndPin();
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(85, 0)); // Hacky magic number to space out the output pin.
|
||||
ImGui::SameLine();
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
|
||||
// Tooltip example
|
||||
ImGui::Text("Hover over me");
|
||||
static bool do_tooltip = false;
|
||||
do_tooltip = ImGui::IsItemHovered() ? true : false;
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("- or me");
|
||||
static bool do_adv_tooltip = false;
|
||||
do_adv_tooltip = ImGui::IsItemHovered() ? true : false;
|
||||
|
||||
// Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements
|
||||
// (otherwise a Text+SameLine+Button sequence will have the text a little too high by default)
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Option:");
|
||||
ImGui::SameLine();
|
||||
static char popup_text[128] = "Pick one!";
|
||||
static bool do_popup = false;
|
||||
if (ImGui::Button(popup_text)) {
|
||||
do_popup = true; // Instead of saying OpenPopup() here, we set this bool, which is used later in the Deferred Pop-up Section
|
||||
}
|
||||
ed::EndNode();
|
||||
if (firstframe) {
|
||||
ed::SetNodePosition(popup_id, ImVec2(610, 20));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
// Deferred Pop-up Section
|
||||
|
||||
// This entire section needs to be bounded by Suspend/Resume! These calls pop us out of "node canvas coordinates"
|
||||
// and draw the popups in a reasonable screen location.
|
||||
ed::Suspend();
|
||||
// There is some stately stuff happening here. You call "open popup" exactly once, and this
|
||||
// causes it to stick open for many frames until the user makes a selection in the popup, or clicks off to dismiss.
|
||||
// More importantly, this is done inside Suspend(), so it loads the popup with the correct screen coordinates!
|
||||
if (do_popup) {
|
||||
ImGui::OpenPopup("popup_button"); // Cause openpopup to stick open.
|
||||
do_popup = false; // disable bool so that if we click off the popup, it doesn't open the next frame.
|
||||
}
|
||||
|
||||
// This is the actual popup Gui drawing section.
|
||||
if (ImGui::BeginPopup("popup_button")) {
|
||||
// Note: if it weren't for the child window, we would have to PushItemWidth() here to avoid a crash!
|
||||
ImGui::TextDisabled("Pick One:");
|
||||
ImGui::BeginChild("popup_scroller", ImVec2(100, 100), true, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
||||
if (ImGui::Button("Option 1")) {
|
||||
portable_strcpy(popup_text, "Option 1");
|
||||
ImGui::CloseCurrentPopup(); // These calls revoke the popup open state, which was set by OpenPopup above.
|
||||
}
|
||||
if (ImGui::Button("Option 2")) {
|
||||
portable_strcpy(popup_text, "Option 2");
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Option 3")) {
|
||||
portable_strcpy(popup_text, "Option 3");
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (ImGui::Button("Option 4")) {
|
||||
portable_strcpy(popup_text, "Option 4");
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndPopup(); // Note this does not do anything to the popup open/close state. It just terminates the content declaration.
|
||||
}
|
||||
|
||||
// Handle the simple tooltip
|
||||
if (do_tooltip)
|
||||
ImGui::SetTooltip("I am a tooltip");
|
||||
|
||||
// Handle the advanced tooltip
|
||||
if (do_adv_tooltip) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("I am a fancy tooltip");
|
||||
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
|
||||
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ed::Resume();
|
||||
// End of "Deferred Pop-up section"
|
||||
|
||||
|
||||
|
||||
// Plot Widgets =========================================================================================
|
||||
// Note: most of these plots can't be used in nodes missing, because they spawn tooltips automatically,
|
||||
// so we can't trap them in our deferred pop-up mechanism. This causes them to fly into a random screen
|
||||
// location.
|
||||
auto plot_id = uniqueId++;
|
||||
ed::BeginNode(plot_id);
|
||||
ImGui::Text("Plot Demo");
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Input);
|
||||
ImGui::Text("-> In");
|
||||
ed::EndPin();
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(250, 0)); // Hacky magic number to space out the output pin.
|
||||
ImGui::SameLine();
|
||||
ed::BeginPin(uniqueId++, ed::PinKind::Output);
|
||||
ImGui::Text("Out ->");
|
||||
ed::EndPin();
|
||||
|
||||
ImGui::PushItemWidth(300);
|
||||
|
||||
// Animate a simple progress bar
|
||||
static float progress = 0.0f, progress_dir = 1.0f;
|
||||
progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
|
||||
if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
|
||||
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
|
||||
|
||||
|
||||
// Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
|
||||
// or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
|
||||
ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::Text("Progress Bar");
|
||||
|
||||
float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress;
|
||||
char buf[32];
|
||||
portable_sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
|
||||
ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ed::EndNode();
|
||||
if (firstframe) {
|
||||
ed::SetNodePosition(plot_id, ImVec2(850, 20));
|
||||
}
|
||||
// ==================================================================================================
|
||||
// Link Drawing Section
|
||||
|
||||
for (auto& linkInfo : m_Links)
|
||||
ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId);
|
||||
|
||||
// ==================================================================================================
|
||||
// Interaction Handling Section
|
||||
// This was coppied from BasicInteration.cpp. See that file for commented code.
|
||||
|
||||
// Handle creation action ---------------------------------------------------------------------------
|
||||
if (ed::BeginCreate())
|
||||
{
|
||||
ed::PinId inputPinId, outputPinId;
|
||||
if (ed::QueryNewLink(&inputPinId, &outputPinId))
|
||||
{
|
||||
if (inputPinId && outputPinId)
|
||||
{
|
||||
if (ed::AcceptNewItem())
|
||||
{
|
||||
m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId });
|
||||
ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ed::EndCreate();
|
||||
|
||||
// Handle deletion action ---------------------------------------------------------------------------
|
||||
if (ed::BeginDelete())
|
||||
{
|
||||
ed::LinkId deletedLinkId;
|
||||
while (ed::QueryDeletedLink(&deletedLinkId))
|
||||
{
|
||||
if (ed::AcceptDeletedItem())
|
||||
{
|
||||
for (auto& link : m_Links)
|
||||
{
|
||||
if (link.Id == deletedLinkId)
|
||||
{
|
||||
m_Links.erase(&link);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ed::EndDelete();
|
||||
|
||||
ed::End();
|
||||
ed::SetCurrentEditor(nullptr);
|
||||
firstframe = false;
|
||||
//ImGui::ShowMetricsWindow();
|
||||
//ImGui::ShowDemoWindow();
|
||||
}
|
||||
|
||||
ed::EditorContext* m_Context = nullptr;
|
||||
|
||||
ImVector<LinkInfo> m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
||||
int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure.
|
||||
};
|
||||
|
||||
int Main(int argc, char** argv)
|
||||
{
|
||||
Example exampe("Widgets", argc, argv);
|
||||
|
||||
if (exampe.Create())
|
||||
return exampe.Run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user