feat(shaders_lab): visual node editor (imgui-node-editor) + multi-source
- cpp/vendor/imgui-node-editor: vendorized thedmd/imgui-node-editor v0.9.4 - cpp/functions/gfx/dag_node_editor: new visual pipeline editor replacing dag_panel - DagStep: source_ids[4] + editor_pos + editor_uid (multi-input support) - DagNodeDef: num_inputs explicit; circle reclassified as Op - dag_compile: N inputs per node, topological ordering preserved - main: use node editor; destroy on shutdown - patch imgui_extra_math.inl: guard operator*(float, ImVec2) for imgui >= 18955 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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)
|
||||
@@ -0,0 +1,109 @@
|
||||
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)
|
||||
|
||||
target_include_directories(application PRIVATE ${OPENGL_INCLUDE_DIR})
|
||||
target_link_libraries(application PRIVATE ${OPENGL_gl_LIBRARY})
|
||||
list(APPEND _Application_Sources
|
||||
source/imgui_impl_opengl3.cpp
|
||||
source/imgui_impl_opengl3.h
|
||||
source/imgui_impl_opengl3_loader.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")
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# pragma once
|
||||
|
||||
# cmakedefine01 HAVE_GLFW3
|
||||
# cmakedefine01 HAVE_OPENGL
|
||||
@@ -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
|
||||
@@ -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
|
||||
+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;
|
||||
}
|
||||
@@ -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);
|
||||
+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();
|
||||
}
|
||||
@@ -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);
|
||||
+947
@@ -0,0 +1,947 @@
|
||||
// dear imgui: Renderer Backend 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 Backend (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: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accomodating for NetBSD systems having only "libGL.so.3" available. (#6983)
|
||||
// 2023-10-05: OpenGL: Rename symbols in our internal loader so that LTO compilation with another copy of gl3w is possible. (#6875, #6668, #4445)
|
||||
// 2023-06-20: OpenGL: Fixed erroneous use glGetIntegerv(GL_CONTEXT_PROFILE_MASK) on contexts lower than 3.2. (#6539, #6333)
|
||||
// 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375)
|
||||
// 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333)
|
||||
// 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224)
|
||||
// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530)
|
||||
// 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224)
|
||||
// 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes).
|
||||
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||
// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
|
||||
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
|
||||
// 2022-05-13: OpenGL: Fixed state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
|
||||
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
|
||||
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
|
||||
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
|
||||
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
|
||||
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
||||
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||
// 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 nullptr 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"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h> // intptr_t
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
// Clang/GCC warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used
|
||||
#pragma clang diagnostic ignored "-Wnonportable-system-include-path"
|
||||
#pragma clang diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||
#endif
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES2/gl.h> // Use GL ES 2
|
||||
#else
|
||||
#include <GLES2/gl2.h> // Use GL ES 2
|
||||
#endif
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#ifndef GL_GLEXT_PROTOTYPES
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
#include <GLES2/gl2ext.h>
|
||||
#endif
|
||||
#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
|
||||
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
// 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 using our own minimal custom loader based on gl3w.
|
||||
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
|
||||
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
|
||||
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
|
||||
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
|
||||
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
|
||||
#define IMGL3W_IMPL
|
||||
#include "imgui_impl_opengl3_loader.h"
|
||||
#endif
|
||||
|
||||
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
|
||||
#endif
|
||||
|
||||
// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
|
||||
#ifdef GL_POLYGON_MODE
|
||||
#define IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
#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
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler()
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && (defined(IMGUI_IMPL_OPENGL_ES3) || defined(GL_VERSION_3_3))
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
#endif
|
||||
|
||||
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
#endif
|
||||
|
||||
// Desktop GL use extension detection
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||
#endif
|
||||
|
||||
// [Debugging]
|
||||
//#define IMGUI_IMPL_OPENGL_DEBUG
|
||||
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||
#include <stdio.h>
|
||||
#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
|
||||
#else
|
||||
#define GL_CALL(_CALL) _CALL // Call without error check
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
struct ImGui_ImplOpenGL3_Data
|
||||
{
|
||||
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||
bool GlProfileIsES2;
|
||||
bool GlProfileIsES3;
|
||||
bool GlProfileIsCompat;
|
||||
GLint GlProfileMask;
|
||||
GLuint FontTexture;
|
||||
GLuint ShaderHandle;
|
||||
GLint AttribLocationTex; // Uniforms location
|
||||
GLint AttribLocationProjMtx;
|
||||
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||
GLuint AttribLocationVtxUV;
|
||||
GLuint AttribLocationVtxColor;
|
||||
unsigned int VboHandle, ElementsHandle;
|
||||
GLsizeiptr VertexBufferSize;
|
||||
GLsizeiptr IndexBufferSize;
|
||||
bool HasClipOrigin;
|
||||
bool UseBufferSubData;
|
||||
|
||||
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
struct ImGui_ImplOpenGL3_VtxAttribState
|
||||
{
|
||||
GLint Enabled, Size, Type, Normalized, Stride;
|
||||
GLvoid* Ptr;
|
||||
|
||||
void GetState(GLint index)
|
||||
{
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
|
||||
glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
|
||||
}
|
||||
void SetState(GLint index)
|
||||
{
|
||||
glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
|
||||
if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
|
||||
// Initialize our loader
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
if (imgl3wInit() != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
|
||||
// Query for GL version (e.g. 320 for GL 3.2)
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GLES 2
|
||||
bd->GlVersion = 200;
|
||||
bd->GlProfileIsES2 = true;
|
||||
#else
|
||||
// Desktop or GLES 3
|
||||
GLint major = 0;
|
||||
GLint minor = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
if (major == 0 && minor == 0)
|
||||
{
|
||||
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
const char* gl_version = (const char*)glGetString(GL_VERSION);
|
||||
sscanf(gl_version, "%d.%d", &major, &minor);
|
||||
}
|
||||
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||
#if defined(GL_CONTEXT_PROFILE_MASK)
|
||||
if (bd->GlVersion >= 320)
|
||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
|
||||
bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
|
||||
#endif
|
||||
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
bd->GlProfileIsES3 = true;
|
||||
#endif
|
||||
|
||||
bd->UseBufferSubData = false;
|
||||
/*
|
||||
// Query vendor to enable glBufferSubData kludge
|
||||
#ifdef _WIN32
|
||||
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
|
||||
if (strncmp(vendor, "Intel", 5) == 0)
|
||||
bd->UseBufferSubData = true;
|
||||
#endif
|
||||
*/
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||
printf("GlVersion = %d\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->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 nullptr if unsure.
|
||||
if (glsl_version == nullptr)
|
||||
{
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
glsl_version = "#version 100";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
glsl_version = "#version 300 es";
|
||||
#elif defined(__APPLE__)
|
||||
glsl_version = "#version 150";
|
||||
#else
|
||||
glsl_version = "#version 130";
|
||||
#endif
|
||||
}
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
|
||||
strcpy(bd->GlslVersionString, glsl_version);
|
||||
strcat(bd->GlslVersionString, "\n");
|
||||
|
||||
// Make an arbitrary GL call (we don't actually need the result)
|
||||
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
// Detect extensions we support
|
||||
bd->HasClipOrigin = (bd->GlVersion >= 450);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||
GLint num_extensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||
for (GLint i = 0; i < num_extensions; i++)
|
||||
{
|
||||
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||
if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
|
||||
bd->HasClipOrigin = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplOpenGL3_Init()?");
|
||||
|
||||
if (!bd->ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310)
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
|
||||
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
|
||||
#if defined(GL_CLIP_ORIGIN)
|
||||
bool clip_origin_lower_left = true;
|
||||
if (bd->HasClipOrigin)
|
||||
{
|
||||
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.
|
||||
GL_CALL(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 defined(GL_CLIP_ORIGIN)
|
||||
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||
#endif
|
||||
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(bd->ShaderHandle);
|
||||
glUniform1i(bd->AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
|
||||
#endif
|
||||
|
||||
(void)vertex_array_object;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle));
|
||||
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, pos)));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, uv)));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)));
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||
// This is in order to be able to run within an 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;
|
||||
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// 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 IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
GLuint last_sampler; if (bd->GlVersion >= 330 || bd->GlProfileIsES3) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
// This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
|
||||
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_HAS_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_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GL_CALL(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
|
||||
// - OpenGL drivers are in a very sorry state nowadays....
|
||||
// During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
|
||||
// of leaks on Intel GPU when using multi-viewports on Windows.
|
||||
// - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel.
|
||||
// - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code.
|
||||
// We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path.
|
||||
// - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues.
|
||||
const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
|
||||
const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
|
||||
if (bd->UseBufferSubData)
|
||||
{
|
||||
if (bd->VertexBufferSize < vtx_buffer_size)
|
||||
{
|
||||
bd->VertexBufferSize = vtx_buffer_size;
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||
}
|
||||
if (bd->IndexBufferSize < idx_buffer_size)
|
||||
{
|
||||
bd->IndexBufferSize = idx_buffer_size;
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||
}
|
||||
GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data));
|
||||
GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data));
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW));
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (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 != nullptr)
|
||||
{
|
||||
// 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
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||
GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
|
||||
|
||||
// Bind texture, Draw
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
GL_CALL(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
|
||||
GL_CALL(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
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GL_CALL(glDeleteVertexArrays(1, &vertex_array_object));
|
||||
#endif
|
||||
|
||||
// Restore modified GL state
|
||||
// This "glIsProgram()" check is required because if the program is "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220.
|
||||
if (last_program == 0 || glIsProgram(last_program)) glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array_object);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||
last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
|
||||
last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
|
||||
last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
|
||||
#endif
|
||||
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_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
// Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons
|
||||
if (bd->GlVersion <= 310 || bd->GlProfileIsCompat)
|
||||
{
|
||||
glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]);
|
||||
glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
}
|
||||
#endif // IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
|
||||
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]);
|
||||
(void)bd; // Not all compilation paths use this
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
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
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
GLint last_texture;
|
||||
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
||||
GL_CALL(glGenTextures(1, &bd->FontTexture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
#endif
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
// Restore state
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
glDeleteTextures(1, &bd->FontTexture);
|
||||
io.Fonts->SetTexID(0);
|
||||
bd->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)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
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! With GLSL: %s\n", desc, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetShaderInfoLog(handle, log_length, nullptr, (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)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
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, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLint last_vertex_array;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#endif
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(bd->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 highp 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"
|
||||
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\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"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\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"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\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"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
// Select shaders matching our GLSL versions
|
||||
const GLchar* vertex_shader = nullptr;
|
||||
const GLchar* fragment_shader = nullptr;
|
||||
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] = { bd->GlslVersionString, vertex_shader };
|
||||
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr);
|
||||
glCompileShader(vert_handle);
|
||||
CheckShader(vert_handle, "vertex shader");
|
||||
|
||||
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
|
||||
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr);
|
||||
glCompileShader(frag_handle);
|
||||
CheckShader(frag_handle, "fragment shader");
|
||||
|
||||
// Link
|
||||
bd->ShaderHandle = glCreateProgram();
|
||||
glAttachShader(bd->ShaderHandle, vert_handle);
|
||||
glAttachShader(bd->ShaderHandle, frag_handle);
|
||||
glLinkProgram(bd->ShaderHandle);
|
||||
CheckProgram(bd->ShaderHandle, "shader program");
|
||||
|
||||
glDetachShader(bd->ShaderHandle, vert_handle);
|
||||
glDetachShader(bd->ShaderHandle, frag_handle);
|
||||
glDeleteShader(vert_handle);
|
||||
glDeleteShader(frag_handle);
|
||||
|
||||
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
|
||||
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
||||
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
|
||||
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
|
||||
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
|
||||
|
||||
// Create buffers
|
||||
glGenBuffers(1, &bd->VboHandle);
|
||||
glGenBuffers(1, &bd->ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
|
||||
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
|
||||
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// dear imgui: Renderer Backend 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 Backend (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: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
// - This is done automatically on iOS, Android and Emscripten targets.
|
||||
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
// Learn about Dear ImGui:
|
||||
// - FAQ https://dearimgui.com/faq
|
||||
// - Getting Started https://dearimgui.com/getting-started
|
||||
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||
// - Introduction, links and more at the top of imgui.cpp
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter should be nullptr (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
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
|
||||
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
|
||||
|
||||
// You can explicitly select GLES2 or GLES3 API 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)
|
||||
|
||||
// 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__) || defined(__amigaos4__)
|
||||
#define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
|
||||
#else
|
||||
// Otherwise imgui_impl_opengl3_loader.h will be used.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
+810
@@ -0,0 +1,810 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// About imgui_impl_opengl3_loader.h:
|
||||
//
|
||||
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
|
||||
// which proved to be endless problems for users.
|
||||
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
|
||||
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
|
||||
//
|
||||
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
|
||||
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
|
||||
//
|
||||
// IF YOU GET BUILD ERRORS IN THIS FILE (commonly macro redefinitions or function redefinitions):
|
||||
// IT LIKELY MEANS THAT YOU ARE BUILDING 'imgui_impl_opengl3.cpp' OR INCUDING 'imgui_impl_opengl3_loader.h'
|
||||
// IN THE SAME COMPILATION UNIT AS ONE OF YOUR FILE WHICH IS USING A THIRD-PARTY OPENGL LOADER.
|
||||
// (e.g. COULD HAPPEN IF YOU ARE DOING A UNITY/JUMBO BUILD, OR INCLUDING .CPP FILES FROM OTHERS)
|
||||
// YOU SHOULD NOT BUILD BOTH IN THE SAME COMPILATION UNIT.
|
||||
// BUT IF YOU REALLY WANT TO, you can '#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM' and imgui_impl_opengl3.cpp
|
||||
// WILL NOT BE USING OUR LOADER, AND INSTEAD EXPECT ANOTHER/YOUR LOADER TO BE AVAILABLE IN THE COMPILATION UNIT.
|
||||
//
|
||||
// Regenerate with:
|
||||
// python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
|
||||
//
|
||||
// More info:
|
||||
// https://github.com/dearimgui/gl3w_stripped
|
||||
// https://github.com/ocornut/imgui/issues/4445
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* This file was generated with gl3w_gen.py, part of imgl3w
|
||||
* (hosted at https://github.com/dearimgui/gl3w_stripped)
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
* distribute this software, either in source code form or as a compiled
|
||||
* binary, for any purpose, commercial or non-commercial, and by any
|
||||
* means.
|
||||
*
|
||||
* In jurisdictions that recognize copyright laws, the author or authors
|
||||
* of this software dedicate any and all copyright interest in the
|
||||
* software to the public domain. We make this dedication for the benefit
|
||||
* of the public at large and to the detriment of our heirs and
|
||||
* successors. We intend this dedication to be an overt act of
|
||||
* relinquishment in perpetuity of all present and future rights to this
|
||||
* software under copyright law.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __gl3w_h_
|
||||
#define __gl3w_h_
|
||||
|
||||
// Adapted from KHR/khrplatform.h to avoid including entire file.
|
||||
#ifndef __khrplatform_h_
|
||||
typedef float khronos_float_t;
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
typedef signed __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
|
||||
#include <stdint.h>
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#else
|
||||
typedef signed long long khronos_int64_t;
|
||||
typedef unsigned long long khronos_uint64_t;
|
||||
#endif
|
||||
#endif // __khrplatform_h_
|
||||
|
||||
#ifndef __gl_glcorearb_h_
|
||||
#define __gl_glcorearb_h_ 1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
** Copyright 2013-2020 The Khronos Group Inc.
|
||||
** SPDX-License-Identifier: MIT
|
||||
**
|
||||
** This header is generated from the Khronos OpenGL / OpenGL ES XML
|
||||
** API Registry. The current version of the Registry, generator scripts
|
||||
** used to make the header, and the header can be found at
|
||||
** https://github.com/KhronosGroup/OpenGL-Registry
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY *
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
/* glcorearb.h is for use with OpenGL core profile implementations.
|
||||
** It should should be placed in the same directory as gl.h and
|
||||
** included as <GL/glcorearb.h>.
|
||||
**
|
||||
** glcorearb.h includes only APIs in the latest OpenGL core profile
|
||||
** implementation together with APIs in newer ARB extensions which
|
||||
** can be supported by the core profile. It does not, and never will
|
||||
** include functionality removed from the core profile, such as
|
||||
** fixed-function vertex and fragment processing.
|
||||
**
|
||||
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
|
||||
** <GL/glext.h> in the same source file.
|
||||
*/
|
||||
/* Generated C header for:
|
||||
* API: gl
|
||||
* Profile: core
|
||||
* Versions considered: .*
|
||||
* Versions emitted: .*
|
||||
* Default extensions included: glcore
|
||||
* Additional extensions included: _nomatch_^
|
||||
* Extensions removed: _nomatch_^
|
||||
*/
|
||||
#ifndef GL_VERSION_1_0
|
||||
typedef void GLvoid;
|
||||
typedef unsigned int GLenum;
|
||||
|
||||
typedef khronos_float_t GLfloat;
|
||||
typedef int GLint;
|
||||
typedef int GLsizei;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef double GLdouble;
|
||||
typedef unsigned int GLuint;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef khronos_uint8_t GLubyte;
|
||||
#define GL_COLOR_BUFFER_BIT 0x00004000
|
||||
#define GL_FALSE 0
|
||||
#define GL_TRUE 1
|
||||
#define GL_TRIANGLES 0x0004
|
||||
#define GL_ONE 1
|
||||
#define GL_SRC_ALPHA 0x0302
|
||||
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
|
||||
#define GL_FRONT 0x0404
|
||||
#define GL_BACK 0x0405
|
||||
#define GL_FRONT_AND_BACK 0x0408
|
||||
#define GL_POLYGON_MODE 0x0B40
|
||||
#define GL_CULL_FACE 0x0B44
|
||||
#define GL_DEPTH_TEST 0x0B71
|
||||
#define GL_STENCIL_TEST 0x0B90
|
||||
#define GL_VIEWPORT 0x0BA2
|
||||
#define GL_BLEND 0x0BE2
|
||||
#define GL_SCISSOR_BOX 0x0C10
|
||||
#define GL_SCISSOR_TEST 0x0C11
|
||||
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||
#define GL_PACK_ALIGNMENT 0x0D05
|
||||
#define GL_TEXTURE_2D 0x0DE1
|
||||
#define GL_UNSIGNED_BYTE 0x1401
|
||||
#define GL_UNSIGNED_SHORT 0x1403
|
||||
#define GL_UNSIGNED_INT 0x1405
|
||||
#define GL_FLOAT 0x1406
|
||||
#define GL_RGBA 0x1908
|
||||
#define GL_FILL 0x1B02
|
||||
#define GL_VENDOR 0x1F00
|
||||
#define GL_RENDERER 0x1F01
|
||||
#define GL_VERSION 0x1F02
|
||||
#define GL_EXTENSIONS 0x1F03
|
||||
#define GL_LINEAR 0x2601
|
||||
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
|
||||
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
|
||||
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLFLUSHPROC) (void);
|
||||
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
|
||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
|
||||
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
|
||||
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
|
||||
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
GLAPI void APIENTRY glClear (GLbitfield mask);
|
||||
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
GLAPI void APIENTRY glDisable (GLenum cap);
|
||||
GLAPI void APIENTRY glEnable (GLenum cap);
|
||||
GLAPI void APIENTRY glFlush (void);
|
||||
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
|
||||
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
GLAPI GLenum APIENTRY glGetError (void);
|
||||
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
|
||||
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
|
||||
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
|
||||
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_0 */
|
||||
#ifndef GL_VERSION_1_1
|
||||
typedef khronos_float_t GLclampf;
|
||||
typedef double GLclampd;
|
||||
#define GL_TEXTURE_BINDING_2D 0x8069
|
||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
|
||||
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
|
||||
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
|
||||
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
|
||||
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
|
||||
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_1 */
|
||||
#ifndef GL_VERSION_1_3
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#define GL_ACTIVE_TEXTURE 0x84E0
|
||||
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glActiveTexture (GLenum texture);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_3 */
|
||||
#ifndef GL_VERSION_1_4
|
||||
#define GL_BLEND_DST_RGB 0x80C8
|
||||
#define GL_BLEND_SRC_RGB 0x80C9
|
||||
#define GL_BLEND_DST_ALPHA 0x80CA
|
||||
#define GL_BLEND_SRC_ALPHA 0x80CB
|
||||
#define GL_FUNC_ADD 0x8006
|
||||
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
|
||||
GLAPI void APIENTRY glBlendEquation (GLenum mode);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_4 */
|
||||
#ifndef GL_VERSION_1_5
|
||||
typedef khronos_ssize_t GLsizeiptr;
|
||||
typedef khronos_intptr_t GLintptr;
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
|
||||
#define GL_ARRAY_BUFFER_BINDING 0x8894
|
||||
#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
|
||||
#define GL_STREAM_DRAW 0x88E0
|
||||
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
|
||||
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
|
||||
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
|
||||
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
|
||||
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
|
||||
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
#endif
|
||||
#endif /* GL_VERSION_1_5 */
|
||||
#ifndef GL_VERSION_2_0
|
||||
typedef char GLchar;
|
||||
typedef khronos_int16_t GLshort;
|
||||
typedef khronos_int8_t GLbyte;
|
||||
typedef khronos_uint16_t GLushort;
|
||||
#define GL_BLEND_EQUATION_RGB 0x8009
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
|
||||
#define GL_BLEND_EQUATION_ALPHA 0x883D
|
||||
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
|
||||
#define GL_FRAGMENT_SHADER 0x8B30
|
||||
#define GL_VERTEX_SHADER 0x8B31
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
#define GL_LINK_STATUS 0x8B82
|
||||
#define GL_INFO_LOG_LENGTH 0x8B84
|
||||
#define GL_CURRENT_PROGRAM 0x8B8D
|
||||
#define GL_UPPER_LEFT 0x8CA2
|
||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
|
||||
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
|
||||
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
|
||||
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
|
||||
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
|
||||
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
|
||||
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
|
||||
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
|
||||
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
|
||||
GLAPI void APIENTRY glCompileShader (GLuint shader);
|
||||
GLAPI GLuint APIENTRY glCreateProgram (void);
|
||||
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
|
||||
GLAPI void APIENTRY glDeleteProgram (GLuint program);
|
||||
GLAPI void APIENTRY glDeleteShader (GLuint shader);
|
||||
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
|
||||
GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
|
||||
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
|
||||
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
|
||||
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
|
||||
GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
|
||||
GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
|
||||
GLAPI void APIENTRY glLinkProgram (GLuint program);
|
||||
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
GLAPI void APIENTRY glUseProgram (GLuint program);
|
||||
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
|
||||
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
#endif
|
||||
#endif /* GL_VERSION_2_0 */
|
||||
#ifndef GL_VERSION_3_0
|
||||
typedef khronos_uint16_t GLhalf;
|
||||
#define GL_MAJOR_VERSION 0x821B
|
||||
#define GL_MINOR_VERSION 0x821C
|
||||
#define GL_NUM_EXTENSIONS 0x821D
|
||||
#define GL_FRAMEBUFFER_SRGB 0x8DB9
|
||||
#define GL_VERTEX_ARRAY_BINDING 0x85B5
|
||||
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
|
||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
|
||||
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
|
||||
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
|
||||
GLAPI void APIENTRY glBindVertexArray (GLuint array);
|
||||
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
|
||||
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_0 */
|
||||
#ifndef GL_VERSION_3_1
|
||||
#define GL_VERSION_3_1 1
|
||||
#define GL_PRIMITIVE_RESTART 0x8F9D
|
||||
#endif /* GL_VERSION_3_1 */
|
||||
#ifndef GL_VERSION_3_2
|
||||
#define GL_VERSION_3_2 1
|
||||
typedef struct __GLsync *GLsync;
|
||||
typedef khronos_uint64_t GLuint64;
|
||||
typedef khronos_int64_t GLint64;
|
||||
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
|
||||
#define GL_CONTEXT_PROFILE_MASK 0x9126
|
||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_2 */
|
||||
#ifndef GL_VERSION_3_3
|
||||
#define GL_VERSION_3_3 1
|
||||
#define GL_SAMPLER_BINDING 0x8919
|
||||
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
|
||||
#endif
|
||||
#endif /* GL_VERSION_3_3 */
|
||||
#ifndef GL_VERSION_4_1
|
||||
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
|
||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
|
||||
#endif /* GL_VERSION_4_1 */
|
||||
#ifndef GL_VERSION_4_3
|
||||
typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
#endif /* GL_VERSION_4_3 */
|
||||
#ifndef GL_VERSION_4_5
|
||||
#define GL_CLIP_ORIGIN 0x935C
|
||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
|
||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
|
||||
#endif /* GL_VERSION_4_5 */
|
||||
#ifndef GL_ARB_bindless_texture
|
||||
typedef khronos_uint64_t GLuint64EXT;
|
||||
#endif /* GL_ARB_bindless_texture */
|
||||
#ifndef GL_ARB_cl_event
|
||||
struct _cl_context;
|
||||
struct _cl_event;
|
||||
#endif /* GL_ARB_cl_event */
|
||||
#ifndef GL_ARB_clip_control
|
||||
#define GL_ARB_clip_control 1
|
||||
#endif /* GL_ARB_clip_control */
|
||||
#ifndef GL_ARB_debug_output
|
||||
typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
|
||||
#endif /* GL_ARB_debug_output */
|
||||
#ifndef GL_EXT_EGL_image_storage
|
||||
typedef void *GLeglImageOES;
|
||||
#endif /* GL_EXT_EGL_image_storage */
|
||||
#ifndef GL_EXT_direct_state_access
|
||||
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
|
||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
|
||||
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
|
||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
|
||||
#endif /* GL_EXT_direct_state_access */
|
||||
#ifndef GL_NV_draw_vulkan_image
|
||||
typedef void (APIENTRY *GLVULKANPROCNV)(void);
|
||||
#endif /* GL_NV_draw_vulkan_image */
|
||||
#ifndef GL_NV_gpu_shader5
|
||||
typedef khronos_int64_t GLint64EXT;
|
||||
#endif /* GL_NV_gpu_shader5 */
|
||||
#ifndef GL_NV_vertex_buffer_unified_memory
|
||||
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
|
||||
#endif /* GL_NV_vertex_buffer_unified_memory */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GL3W_API
|
||||
#define GL3W_API
|
||||
#endif
|
||||
|
||||
#ifndef __gl_h_
|
||||
#define __gl_h_
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GL3W_OK 0
|
||||
#define GL3W_ERROR_INIT -1
|
||||
#define GL3W_ERROR_LIBRARY_OPEN -2
|
||||
#define GL3W_ERROR_OPENGL_VERSION -3
|
||||
|
||||
typedef void (*GL3WglProc)(void);
|
||||
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
|
||||
|
||||
/* gl3w api */
|
||||
GL3W_API int imgl3wInit(void);
|
||||
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
|
||||
GL3W_API int imgl3wIsSupported(int major, int minor);
|
||||
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
|
||||
|
||||
/* gl3w internal state */
|
||||
union ImGL3WProcs {
|
||||
GL3WglProc ptr[59];
|
||||
struct {
|
||||
PFNGLACTIVETEXTUREPROC ActiveTexture;
|
||||
PFNGLATTACHSHADERPROC AttachShader;
|
||||
PFNGLBINDBUFFERPROC BindBuffer;
|
||||
PFNGLBINDSAMPLERPROC BindSampler;
|
||||
PFNGLBINDTEXTUREPROC BindTexture;
|
||||
PFNGLBINDVERTEXARRAYPROC BindVertexArray;
|
||||
PFNGLBLENDEQUATIONPROC BlendEquation;
|
||||
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
|
||||
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
|
||||
PFNGLBUFFERDATAPROC BufferData;
|
||||
PFNGLBUFFERSUBDATAPROC BufferSubData;
|
||||
PFNGLCLEARPROC Clear;
|
||||
PFNGLCLEARCOLORPROC ClearColor;
|
||||
PFNGLCOMPILESHADERPROC CompileShader;
|
||||
PFNGLCREATEPROGRAMPROC CreateProgram;
|
||||
PFNGLCREATESHADERPROC CreateShader;
|
||||
PFNGLDELETEBUFFERSPROC DeleteBuffers;
|
||||
PFNGLDELETEPROGRAMPROC DeleteProgram;
|
||||
PFNGLDELETESHADERPROC DeleteShader;
|
||||
PFNGLDELETETEXTURESPROC DeleteTextures;
|
||||
PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
|
||||
PFNGLDETACHSHADERPROC DetachShader;
|
||||
PFNGLDISABLEPROC Disable;
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC DisableVertexAttribArray;
|
||||
PFNGLDRAWELEMENTSPROC DrawElements;
|
||||
PFNGLDRAWELEMENTSBASEVERTEXPROC DrawElementsBaseVertex;
|
||||
PFNGLENABLEPROC Enable;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
|
||||
PFNGLFLUSHPROC Flush;
|
||||
PFNGLGENBUFFERSPROC GenBuffers;
|
||||
PFNGLGENTEXTURESPROC GenTextures;
|
||||
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
|
||||
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
|
||||
PFNGLGETERRORPROC GetError;
|
||||
PFNGLGETINTEGERVPROC GetIntegerv;
|
||||
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
|
||||
PFNGLGETPROGRAMIVPROC GetProgramiv;
|
||||
PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
|
||||
PFNGLGETSHADERIVPROC GetShaderiv;
|
||||
PFNGLGETSTRINGPROC GetString;
|
||||
PFNGLGETSTRINGIPROC GetStringi;
|
||||
PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
|
||||
PFNGLGETVERTEXATTRIBPOINTERVPROC GetVertexAttribPointerv;
|
||||
PFNGLGETVERTEXATTRIBIVPROC GetVertexAttribiv;
|
||||
PFNGLISENABLEDPROC IsEnabled;
|
||||
PFNGLISPROGRAMPROC IsProgram;
|
||||
PFNGLLINKPROGRAMPROC LinkProgram;
|
||||
PFNGLPIXELSTOREIPROC PixelStorei;
|
||||
PFNGLPOLYGONMODEPROC PolygonMode;
|
||||
PFNGLREADPIXELSPROC ReadPixels;
|
||||
PFNGLSCISSORPROC Scissor;
|
||||
PFNGLSHADERSOURCEPROC ShaderSource;
|
||||
PFNGLTEXIMAGE2DPROC TexImage2D;
|
||||
PFNGLTEXPARAMETERIPROC TexParameteri;
|
||||
PFNGLUNIFORM1IPROC Uniform1i;
|
||||
PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv;
|
||||
PFNGLUSEPROGRAMPROC UseProgram;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
|
||||
PFNGLVIEWPORTPROC Viewport;
|
||||
} gl;
|
||||
};
|
||||
|
||||
GL3W_API extern union ImGL3WProcs imgl3wProcs;
|
||||
|
||||
/* OpenGL functions */
|
||||
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
|
||||
#define glAttachShader imgl3wProcs.gl.AttachShader
|
||||
#define glBindBuffer imgl3wProcs.gl.BindBuffer
|
||||
#define glBindSampler imgl3wProcs.gl.BindSampler
|
||||
#define glBindTexture imgl3wProcs.gl.BindTexture
|
||||
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
|
||||
#define glBlendEquation imgl3wProcs.gl.BlendEquation
|
||||
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
|
||||
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
|
||||
#define glBufferData imgl3wProcs.gl.BufferData
|
||||
#define glBufferSubData imgl3wProcs.gl.BufferSubData
|
||||
#define glClear imgl3wProcs.gl.Clear
|
||||
#define glClearColor imgl3wProcs.gl.ClearColor
|
||||
#define glCompileShader imgl3wProcs.gl.CompileShader
|
||||
#define glCreateProgram imgl3wProcs.gl.CreateProgram
|
||||
#define glCreateShader imgl3wProcs.gl.CreateShader
|
||||
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
|
||||
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
|
||||
#define glDeleteShader imgl3wProcs.gl.DeleteShader
|
||||
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
|
||||
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
|
||||
#define glDetachShader imgl3wProcs.gl.DetachShader
|
||||
#define glDisable imgl3wProcs.gl.Disable
|
||||
#define glDisableVertexAttribArray imgl3wProcs.gl.DisableVertexAttribArray
|
||||
#define glDrawElements imgl3wProcs.gl.DrawElements
|
||||
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
|
||||
#define glEnable imgl3wProcs.gl.Enable
|
||||
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
|
||||
#define glFlush imgl3wProcs.gl.Flush
|
||||
#define glGenBuffers imgl3wProcs.gl.GenBuffers
|
||||
#define glGenTextures imgl3wProcs.gl.GenTextures
|
||||
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
|
||||
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
|
||||
#define glGetError imgl3wProcs.gl.GetError
|
||||
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
|
||||
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
|
||||
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
|
||||
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
|
||||
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
|
||||
#define glGetString imgl3wProcs.gl.GetString
|
||||
#define glGetStringi imgl3wProcs.gl.GetStringi
|
||||
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
|
||||
#define glGetVertexAttribPointerv imgl3wProcs.gl.GetVertexAttribPointerv
|
||||
#define glGetVertexAttribiv imgl3wProcs.gl.GetVertexAttribiv
|
||||
#define glIsEnabled imgl3wProcs.gl.IsEnabled
|
||||
#define glIsProgram imgl3wProcs.gl.IsProgram
|
||||
#define glLinkProgram imgl3wProcs.gl.LinkProgram
|
||||
#define glPixelStorei imgl3wProcs.gl.PixelStorei
|
||||
#define glPolygonMode imgl3wProcs.gl.PolygonMode
|
||||
#define glReadPixels imgl3wProcs.gl.ReadPixels
|
||||
#define glScissor imgl3wProcs.gl.Scissor
|
||||
#define glShaderSource imgl3wProcs.gl.ShaderSource
|
||||
#define glTexImage2D imgl3wProcs.gl.TexImage2D
|
||||
#define glTexParameteri imgl3wProcs.gl.TexParameteri
|
||||
#define glUniform1i imgl3wProcs.gl.Uniform1i
|
||||
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
|
||||
#define glUseProgram imgl3wProcs.gl.UseProgram
|
||||
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
|
||||
#define glViewport imgl3wProcs.gl.Viewport
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef IMGL3W_IMPL
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define GL3W_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
static HMODULE libgl;
|
||||
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
|
||||
static GL3WglGetProcAddr wgl_get_proc_address;
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = LoadLibraryA("opengl32.dll");
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { FreeLibrary(libgl); }
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
res = (GL3WglProc)wgl_get_proc_address(proc);
|
||||
if (!res)
|
||||
res = (GL3WglProc)GetProcAddress(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { dlclose(libgl); }
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
// While most systems use libGL.so.1, NetBSD seems to use that libGL.so.3. See https://github.com/ocornut/imgui/issues/6983
|
||||
libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { dlclose(libgl); }
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
res = glx_get_proc_address((const GLubyte *)proc);
|
||||
if (!res)
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct { int major, minor; } version;
|
||||
|
||||
static int parse_version(void)
|
||||
{
|
||||
if (!glGetIntegerv)
|
||||
return GL3W_ERROR_INIT;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
|
||||
if (version.major == 0 && version.minor == 0)
|
||||
{
|
||||
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
|
||||
if (const char* gl_version = (const char*)glGetString(GL_VERSION))
|
||||
sscanf(gl_version, "%d.%d", &version.major, &version.minor);
|
||||
}
|
||||
if (version.major < 2)
|
||||
return GL3W_ERROR_OPENGL_VERSION;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc);
|
||||
|
||||
int imgl3wInit(void)
|
||||
{
|
||||
int res = open_libgl();
|
||||
if (res)
|
||||
return res;
|
||||
atexit(close_libgl);
|
||||
return imgl3wInit2(get_proc);
|
||||
}
|
||||
|
||||
int imgl3wInit2(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
load_procs(proc);
|
||||
return parse_version();
|
||||
}
|
||||
|
||||
int imgl3wIsSupported(int major, int minor)
|
||||
{
|
||||
if (major < 2)
|
||||
return 0;
|
||||
if (version.major == major)
|
||||
return version.minor >= minor;
|
||||
return version.major >= major;
|
||||
}
|
||||
|
||||
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
|
||||
|
||||
static const char *proc_names[] = {
|
||||
"glActiveTexture",
|
||||
"glAttachShader",
|
||||
"glBindBuffer",
|
||||
"glBindSampler",
|
||||
"glBindTexture",
|
||||
"glBindVertexArray",
|
||||
"glBlendEquation",
|
||||
"glBlendEquationSeparate",
|
||||
"glBlendFuncSeparate",
|
||||
"glBufferData",
|
||||
"glBufferSubData",
|
||||
"glClear",
|
||||
"glClearColor",
|
||||
"glCompileShader",
|
||||
"glCreateProgram",
|
||||
"glCreateShader",
|
||||
"glDeleteBuffers",
|
||||
"glDeleteProgram",
|
||||
"glDeleteShader",
|
||||
"glDeleteTextures",
|
||||
"glDeleteVertexArrays",
|
||||
"glDetachShader",
|
||||
"glDisable",
|
||||
"glDisableVertexAttribArray",
|
||||
"glDrawElements",
|
||||
"glDrawElementsBaseVertex",
|
||||
"glEnable",
|
||||
"glEnableVertexAttribArray",
|
||||
"glFlush",
|
||||
"glGenBuffers",
|
||||
"glGenTextures",
|
||||
"glGenVertexArrays",
|
||||
"glGetAttribLocation",
|
||||
"glGetError",
|
||||
"glGetIntegerv",
|
||||
"glGetProgramInfoLog",
|
||||
"glGetProgramiv",
|
||||
"glGetShaderInfoLog",
|
||||
"glGetShaderiv",
|
||||
"glGetString",
|
||||
"glGetStringi",
|
||||
"glGetUniformLocation",
|
||||
"glGetVertexAttribPointerv",
|
||||
"glGetVertexAttribiv",
|
||||
"glIsEnabled",
|
||||
"glIsProgram",
|
||||
"glLinkProgram",
|
||||
"glPixelStorei",
|
||||
"glPolygonMode",
|
||||
"glReadPixels",
|
||||
"glScissor",
|
||||
"glShaderSource",
|
||||
"glTexImage2D",
|
||||
"glTexParameteri",
|
||||
"glUniform1i",
|
||||
"glUniformMatrix4fv",
|
||||
"glUseProgram",
|
||||
"glVertexAttribPointer",
|
||||
"glViewport",
|
||||
};
|
||||
|
||||
GL3W_API union ImGL3WProcs imgl3wProcs;
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < GL3W_ARRAY_SIZE(proc_names); i++)
|
||||
imgl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+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);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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();
|
||||
@@ -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)
|
||||
@@ -0,0 +1,208 @@
|
||||
# include "renderer.h"
|
||||
|
||||
# if RENDERER(IMGUI_OGL3)
|
||||
|
||||
# include "platform.h"
|
||||
# include <algorithm>
|
||||
# include <cstdint> // std::intptr_t
|
||||
|
||||
# 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;
|
||||
# elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
# include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||
# else
|
||||
# include "imgui_impl_opengl3_loader.h"
|
||||
# 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)
|
||||
@@ -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()))
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@@ -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>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#define IDI_APPLICATION 32512
|
||||
|
||||
IDI_APPLICATION ICON "${ApplicationIcon}"
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
add_example_executable(basic-interaction-example
|
||||
basic-interaction-example.cpp
|
||||
)
|
||||
Vendored
+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;
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
+1835
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 |
+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
|
||||
//------------------------------------------------------------------------------
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include "builders.h"
|
||||
# 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));
|
||||
}
|
||||
+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
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include "drawing.h"
|
||||
# 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include "widgets.h"
|
||||
# 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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
add_example_executable(canvas-example
|
||||
canvas-example.cpp
|
||||
)
|
||||
|
||||
#target_link_libraries(Canvas PRIVATE imgui_canvas)
|
||||
@@ -0,0 +1,251 @@
|
||||
# define IMGUI_DEFINE_MATH_OPERATORS
|
||||
# include <imgui.h>
|
||||
# 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;
|
||||
}
|
||||
Binary file not shown.
@@ -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.
|
||||
@@ -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.
|
||||
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.
|
||||
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
add_example_executable(simple-example
|
||||
simple-example.cpp
|
||||
)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
add_example_executable(widgets-example
|
||||
widgets-example.cpp
|
||||
)
|
||||
@@ -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