From 4cbd316f0183600222625a9da46ab4786bfe2981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Wed, 9 Mar 2016 16:39:54 +0100 Subject: [PATCH 01/24] Vulkan example. --- examples/vulkan_example/CMakeLists.txt | 36 + examples/vulkan_example/gen_spv.sh | 4 + examples/vulkan_example/glsl_shader.frag | 14 + examples/vulkan_example/glsl_shader.vert | 21 + .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 1017 +++++++++++++++++ .../vulkan_example/imgui_impl_glfw_vulkan.h | 41 + examples/vulkan_example/main.cpp | 533 +++++++++ 7 files changed, 1666 insertions(+) create mode 100644 examples/vulkan_example/CMakeLists.txt create mode 100755 examples/vulkan_example/gen_spv.sh create mode 100644 examples/vulkan_example/glsl_shader.frag create mode 100644 examples/vulkan_example/glsl_shader.vert create mode 100644 examples/vulkan_example/imgui_impl_glfw_vulkan.cpp create mode 100644 examples/vulkan_example/imgui_impl_glfw_vulkan.h create mode 100644 examples/vulkan_example/main.cpp diff --git a/examples/vulkan_example/CMakeLists.txt b/examples/vulkan_example/CMakeLists.txt new file mode 100644 index 000000000..daa7a1716 --- /dev/null +++ b/examples/vulkan_example/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8) +project(ImGuiGLFWVulkanExample C CXX) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) +endif() + +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES") +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES") + +# GLFW +set(GLFW_DIR ../../../glfw) +option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) +option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) +option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) +option(GLFW_INSTALL "Generate installation target" OFF) +option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF) +add_subdirectory(${GLFW_DIR} binary_dir EXCLUDE_FROM_ALL) +include_directories(${GLFW_DIR}/include) + +# ImGui +set(IMGUI_DIR ../../) +include_directories(${IMGUI_DIR}) + +# Libraries +if(WIN32) + set(LIBRARIES "glfw;vulkan-${MAJOR}") +elseif(UNIX) + set(LIBRARIES "glfw;vulkan") +else() +endif() + +file(GLOB sources *.cpp) + +add_executable(vulkan_example ${sources} ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp) +target_link_libraries(vulkan_example ${LIBRARIES}) diff --git a/examples/vulkan_example/gen_spv.sh b/examples/vulkan_example/gen_spv.sh new file mode 100755 index 000000000..f95f8fa88 --- /dev/null +++ b/examples/vulkan_example/gen_spv.sh @@ -0,0 +1,4 @@ +#!/bin/bash +glslangValidator -V -o glsl_shader.frag.spv glsl_shader.frag +glslangValidator -V -o glsl_shader.vert.spv glsl_shader.vert +spirv-remap --map all --dce all --strip-all --input glsl_shader.frag.spv glsl_shader.vert.spv --output ./ diff --git a/examples/vulkan_example/glsl_shader.frag b/examples/vulkan_example/glsl_shader.frag new file mode 100644 index 000000000..8205b673e --- /dev/null +++ b/examples/vulkan_example/glsl_shader.frag @@ -0,0 +1,14 @@ +#version 450 core +layout(location = 0, index = 0) out vec4 fColor; + +layout(set=0, binding=0) uniform sampler2D sTexture; + +in block{ + vec4 Color; + vec2 UV; +} In; + +void main() +{ + fColor = In.Color * texture(sTexture, In.UV.st); +} diff --git a/examples/vulkan_example/glsl_shader.vert b/examples/vulkan_example/glsl_shader.vert new file mode 100644 index 000000000..55098fec6 --- /dev/null +++ b/examples/vulkan_example/glsl_shader.vert @@ -0,0 +1,21 @@ +#version 450 core +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aUV; +layout(location = 2) in vec4 aColor; + +layout(push_constant) uniform uPushConstant{ + vec2 uScale; + vec2 uTranslate; +} pc; + +out block{ + vec4 Color; + vec2 UV; +} Out; + +void main() +{ + Out.Color = aColor; + Out.UV = aUV; + gl_Position = vec4(aPos*pc.uScale+pc.uTranslate, 0, 1); +} diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp new file mode 100644 index 000000000..7ca1ab9fa --- /dev/null +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -0,0 +1,1017 @@ +// ImGui GLFW binding with Vulkan + shaders +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you use this binding you'll need to call 5 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXX_CreateFontsTexture(), ImGui_ImplXXXX_NewFrame(), ImGui_ImplXXXX_Render() and ImGui_ImplXXXX_Shutdown(). +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +#include + +// GLFW +#define GLFW_INCLUDE_NONE +#define GLFW_INCLUDE_VULKAN +#include +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WGL +#include +#endif + +#include "imgui_impl_glfw_vulkan.h" + +// GLFW Data +static GLFWwindow* g_Window = NULL; +static double g_Time = 0.0f; +static bool g_MousePressed[3] = { false, false, false }; +static float g_MouseWheel = 0.0f; + +// Vulkan Data +static VkAllocationCallbacks* g_Allocator = NULL; +static VkPhysicalDevice g_Gpu = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static VkRenderPass g_RenderPass = VK_NULL_HANDLE; +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; +static void (*g_CheckVkResult)(VkResult err) = NULL; + +static VkCommandBuffer g_CommandBuffer = VK_NULL_HANDLE; +static size_t g_BufferMemoryAlignment = 256; +static VkPipelineCreateFlags g_PipelineCreateFlags = 0; +static int g_FrameIndex = 0; + +static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE; +static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE; +static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE; +static VkPipeline g_Pipeline = VK_NULL_HANDLE; + +static VkSampler g_FontSampler = VK_NULL_HANDLE; +static VkDeviceMemory g_FontMemory = VK_NULL_HANDLE; +static VkImage g_FontImage = VK_NULL_HANDLE; +static VkImageView g_FontView = VK_NULL_HANDLE; + +static VkDeviceMemory g_VertexBufferMemory[IMGUI_VK_QUEUED_FRAMES] = {}; +static VkDeviceMemory g_IndexBufferMemory[IMGUI_VK_QUEUED_FRAMES] = {}; +static size_t g_VertexBufferSize[IMGUI_VK_QUEUED_FRAMES] = {}; +static size_t g_IndexBufferSize[IMGUI_VK_QUEUED_FRAMES] = {}; +static VkBuffer g_VertexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; +static VkBuffer g_IndexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; + +static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; +static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; + +static unsigned char __glsl_shader_vert_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x6c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x02, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, + 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x16, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x41, 0x14, 0x00, 0x00, + 0x6a, 0x16, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, 0x80, 0x14, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x41, 0x14, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6a, 0x16, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0xb1, 0x02, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0xb1, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0xb1, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0xb1, 0x02, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x80, 0x14, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x06, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x06, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0xfa, 0x16, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x03, 0x00, 0x02, 0x05, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, + 0x1a, 0x04, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1a, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, + 0x47, 0x11, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x9a, 0x02, 0x00, 0x00, 0x41, 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x9b, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0e, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x90, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, 0x6a, 0x16, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x91, 0x02, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x7f, 0x02, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, + 0xb1, 0x02, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x7f, 0x02, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x2e, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x05, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, + 0x80, 0x14, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x00, + 0x06, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x83, 0x06, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x06, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x83, 0x06, 0x00, 0x00, + 0xfa, 0x16, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x92, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x36, 0x00, 0x05, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x1f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x05, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x6b, 0x60, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x71, 0x4e, 0x00, 0x00, + 0x41, 0x14, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x9b, 0x02, 0x00, 0x00, + 0xaa, 0x26, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0xaa, 0x26, 0x00, 0x00, 0x71, 0x4e, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xda, 0x35, 0x00, 0x00, + 0x6a, 0x16, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x91, 0x02, 0x00, 0x00, + 0xea, 0x50, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0xea, 0x50, 0x00, 0x00, 0xda, 0x35, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xc7, 0x35, 0x00, 0x00, + 0x80, 0x14, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x92, 0x02, 0x00, 0x00, + 0xef, 0x56, 0x00, 0x00, 0xfa, 0x16, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0xe0, 0x29, 0x00, 0x00, + 0xef, 0x56, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, + 0xa0, 0x22, 0x00, 0x00, 0xc7, 0x35, 0x00, 0x00, 0xe0, 0x29, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x92, 0x02, 0x00, 0x00, 0x42, 0x2c, 0x00, 0x00, + 0xfa, 0x16, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x42, 0x2c, 0x00, 0x00, + 0x81, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, + 0xa0, 0x22, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0xa1, 0x41, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x84, 0x36, 0x00, 0x00, 0xd1, 0x4e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x07, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x47, 0x00, 0x00, + 0xa1, 0x41, 0x00, 0x00, 0x84, 0x36, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x9b, 0x02, 0x00, 0x00, + 0x17, 0x2f, 0x00, 0x00, 0x42, 0x13, 0x00, 0x00, 0x0b, 0x0a, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x17, 0x2f, 0x00, 0x00, 0x54, 0x47, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; +static unsigned int __glsl_shader_vert_spv_len = 1172; + +static unsigned char __glsl_shader_frag_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, + 0x6c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1f, 0x16, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x7a, 0x0c, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x1f, 0x16, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x7a, 0x0c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x7a, 0x0c, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1a, 0x04, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xec, 0x14, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0xec, 0x14, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x02, 0x05, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x9a, 0x02, 0x00, 0x00, + 0x7a, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x04, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x97, 0x06, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x97, 0x06, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x9b, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0x96, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x03, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x7b, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x7b, 0x04, 0x00, 0x00, + 0xec, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x90, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1f, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x6b, 0x5d, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x9b, 0x02, 0x00, 0x00, 0x8d, 0x1b, 0x00, 0x00, 0x35, 0x16, 0x00, 0x00, + 0x0b, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x0b, 0x40, 0x00, 0x00, 0x8d, 0x1b, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0xfe, 0x01, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00, 0xec, 0x14, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x90, 0x02, 0x00, 0x00, 0xc2, 0x43, 0x00, 0x00, + 0x35, 0x16, 0x00, 0x00, 0x0e, 0x0a, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0xc2, 0x43, 0x00, 0x00, + 0x57, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xb9, 0x46, 0x00, 0x00, + 0xc0, 0x36, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x1d, 0x00, 0x00, 0x00, 0xe4, 0x23, 0x00, 0x00, 0x0b, 0x40, 0x00, 0x00, + 0xb9, 0x46, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7a, 0x0c, 0x00, 0x00, + 0xe4, 0x23, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; +static unsigned int __glsl_shader_frag_spv_len = 660; + +static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits) +{ + VkPhysicalDeviceMemoryProperties prop; + vkGetPhysicalDeviceMemoryProperties(g_Gpu, &prop); + for(uint32_t i=0; i < prop.memoryTypeCount; ++i) + if((prop.memoryTypes[i].propertyFlags & properties) == properties && + type_bits & (1<TotalVtxCount * sizeof(ImDrawVert); + if(!g_VertexBuffer[g_FrameIndex] || + g_VertexBufferSize[g_FrameIndex] < vertex_size){ + if(g_VertexBuffer[g_FrameIndex]) + vkDestroyBuffer(g_Device, g_VertexBuffer[g_FrameIndex], g_Allocator); + if(g_VertexBufferMemory[g_FrameIndex]) + vkFreeMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], g_Allocator); + size_t vertex_buffer_size = ((vertex_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = vertex_buffer_size; + buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(g_Device, + &buffer_info, + g_Allocator, + &g_VertexBuffer[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(g_Device, g_VertexBuffer[g_FrameIndex], &req); + g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_VertexBufferMemory[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindBufferMemory(g_Device, + g_VertexBuffer[g_FrameIndex], + g_VertexBufferMemory[g_FrameIndex], 0); + ImGui_ImplGlfwVulkan_VkResult(err); + g_VertexBufferSize[g_FrameIndex] = vertex_buffer_size; + } + // Create the Index Buffer: + size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); + if(!g_IndexBuffer[g_FrameIndex] || + g_IndexBufferSize[g_FrameIndex] < index_size){ + if(g_IndexBuffer[g_FrameIndex]) + vkDestroyBuffer(g_Device, g_IndexBuffer[g_FrameIndex], g_Allocator); + if(g_IndexBufferMemory[g_FrameIndex]) + vkFreeMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], g_Allocator); + size_t index_buffer_size = ((index_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = index_buffer_size; + buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(g_Device, + &buffer_info, + g_Allocator, + &g_IndexBuffer[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(g_Device, g_IndexBuffer[g_FrameIndex], &req); + g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_IndexBufferMemory[g_FrameIndex]); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindBufferMemory(g_Device, + g_IndexBuffer[g_FrameIndex], + g_IndexBufferMemory[g_FrameIndex], 0); + ImGui_ImplGlfwVulkan_VkResult(err); + g_IndexBufferSize[g_FrameIndex] = index_buffer_size; + } + // Upload Vertex and index Data: + { + ImDrawVert* vtx_dst; + ImDrawIdx* idx_dst; + err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], + 0, vertex_size, 0, + reinterpret_cast(&vtx_dst)); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], + 0, index_size, 0, + reinterpret_cast(&idx_dst)); + ImGui_ImplGlfwVulkan_VkResult(err); + for(int n = 0; n < draw_data->CmdListsCount; n++){ + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, &cmd_list->VtxBuffer[0], + cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); + memcpy(idx_dst, &cmd_list->IdxBuffer[0], + cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.size(); + idx_dst += cmd_list->IdxBuffer.size(); + } + VkMappedMemoryRange range[2] = {}; + range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[0].memory = g_VertexBufferMemory[g_FrameIndex]; + range[0].size = vertex_size; + range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[1].memory = g_IndexBufferMemory[g_FrameIndex]; + range[1].size = index_size; + err = vkFlushMappedMemoryRanges(g_Device, 2, range); + ImGui_ImplGlfwVulkan_VkResult(err); + vkUnmapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex]); + vkUnmapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex]); + } + // Bind pipeline and descriptor sets: + { + vkCmdBindPipeline(g_CommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + g_Pipeline); + VkDescriptorSet desc_set[1] = {g_DescriptorSet}; + vkCmdBindDescriptorSets(g_CommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + g_PipelineLayout, + 0, 1, desc_set, + 0, NULL); + } + // Bind Vertex And Index Buffer: + { + VkBuffer vertex_buffers[1] = {g_VertexBuffer[g_FrameIndex]}; + VkDeviceSize vertex_offset[1] = {0}; + vkCmdBindVertexBuffers(g_CommandBuffer, + 0, 1, + vertex_buffers, vertex_offset); + vkCmdBindIndexBuffer(g_CommandBuffer, + g_IndexBuffer[g_FrameIndex], + 0, VK_INDEX_TYPE_UINT16); + } + // Setup viewport: + { + VkViewport viewport; + viewport.x = 0; + viewport.y = 0; + viewport.width = ImGui::GetIO().DisplaySize.x; + viewport.height = ImGui::GetIO().DisplaySize.y; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + vkCmdSetViewport(g_CommandBuffer, 0, 1, &viewport); + } + // Setup scale and translation: + { + float scale[2]; + scale[0] = 2.0f/io.DisplaySize.x; + scale[1] = 2.0f/io.DisplaySize.y; + float translate[2]; + translate[0] = -1.0f; + translate[1] = -1.0f; + vkCmdPushConstants(g_CommandBuffer, + g_PipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT, + sizeof(float) * 0, + sizeof(float) * 2, + scale); + vkCmdPushConstants(g_CommandBuffer, + g_PipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT, + sizeof(float) * 2, + sizeof(float) * 2, + translate); + } + // Render the command lists: + int vtx_offset = 0; + int idx_offset = 0; + 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){ + pcmd->UserCallback(cmd_list, pcmd); + } + else{ + VkRect2D scissor; + scissor.offset.x = static_cast(pcmd->ClipRect.x); + scissor.offset.y = static_cast(pcmd->ClipRect.y); + scissor.extent.width = static_cast(pcmd->ClipRect.z - pcmd->ClipRect.x); + scissor.extent.height = static_cast(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? + vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); + vkCmdDrawIndexed(g_CommandBuffer, + pcmd->ElemCount, 1, + idx_offset, vtx_offset, 0); + } + idx_offset += pcmd->ElemCount; + } + vtx_offset += cmd_list->VtxBuffer.size(); + } +} + +static const char* ImGui_ImplGlfwVulkan_GetClipboardText() +{ + return glfwGetClipboardString(g_Window); +} + +static void ImGui_ImplGlfwVulkan_SetClipboardText(const char* text) +{ + glfwSetClipboardString(g_Window, text); +} + +void ImGui_ImplGlfwVulkan_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) +{ + if (action == GLFW_PRESS && button >= 0 && button < 3) + g_MousePressed[button] = true; +} + +void ImGui_ImplGlfwVulkan_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) +{ + g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. +} + +void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow*, int key, int, int action, int mods) +{ + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + + (void)mods; // 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]; +} + +void ImGui_ImplGlfwVulkan_CharCallback(GLFWwindow*, unsigned int c) +{ + ImGuiIO& io = ImGui::GetIO(); + if (c > 0 && c < 0x10000) + io.AddInputCharacter((unsigned short)c); +} + +bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) +{ + ImGuiIO& io = ImGui::GetIO(); + + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + size_t upload_size = width*height*4*sizeof(char); + + VkResult err; + // Create the Image: + { + VkImageCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + info.imageType = VK_IMAGE_TYPE_2D; + info.format = VK_FORMAT_R8G8B8A8_UNORM; + info.extent.width = width; + info.extent.height = height; + info.extent.depth = 1; + info.mipLevels = 1; + info.arrayLayers = 1; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + err = vkCreateImage(g_Device, + &info, + g_Allocator, + &g_FontImage); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetImageMemoryRequirements(g_Device, g_FontImage, &req); + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_FontMemory); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0); + ImGui_ImplGlfwVulkan_VkResult(err); + } + // Create the Image View: + { + VkResult err; + VkImageViewCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + info.image = g_FontImage; + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + info.format = VK_FORMAT_R8G8B8A8_UNORM; + info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + info.subresourceRange.levelCount = 1; + info.subresourceRange.layerCount = 1; + err = vkCreateImageView(g_Device, + &info, + g_Allocator, + &g_FontView); + ImGui_ImplGlfwVulkan_VkResult(err); + } + // Update the Descriptor Set: + { + VkDescriptorImageInfo desc_image[1] = {}; + desc_image[0].sampler = g_FontSampler; + desc_image[0].imageView = g_FontView; + desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + VkWriteDescriptorSet write_desc[1] = {}; + write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_desc[0].dstSet = g_DescriptorSet; + write_desc[0].descriptorCount = 1; + write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write_desc[0].pImageInfo = desc_image; + vkUpdateDescriptorSets(g_Device, + 1, write_desc, + 0, NULL); + } + // Create the Upload Buffer: + { + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = upload_size; + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(g_Device, + &buffer_info, + g_Allocator, + &g_UploadBuffer); + ImGui_ImplGlfwVulkan_VkResult(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req); + g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = req.size; + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + req.memoryTypeBits); + err = vkAllocateMemory(g_Device, + &alloc_info, + g_Allocator, + &g_UploadBufferMemory); + ImGui_ImplGlfwVulkan_VkResult(err); + err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0); + ImGui_ImplGlfwVulkan_VkResult(err); + } + // Upload to Buffer: + { + char *map; + err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, + reinterpret_cast(&map)); + ImGui_ImplGlfwVulkan_VkResult(err); + memcpy(map, pixels, upload_size); + VkMappedMemoryRange range[1] = {}; + range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[0].memory = g_UploadBufferMemory; + range[0].size = upload_size; + err = vkFlushMappedMemoryRanges(g_Device, 1, range); + ImGui_ImplGlfwVulkan_VkResult(err); + vkUnmapMemory(g_Device, g_UploadBufferMemory); + } + // Upload Barrier: + { + VkBufferMemoryBarrier buffer_barrier[1] = {}; + buffer_barrier[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + buffer_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + buffer_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + buffer_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + buffer_barrier[0].buffer = g_UploadBuffer; + buffer_barrier[0].size = upload_size; + VkImageMemoryBarrier image_barrier[1] = {}; + image_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].image = g_FontImage; + image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barrier[0].subresourceRange.levelCount = 1; + image_barrier[0].subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(command_buffer, + VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, NULL, 1, buffer_barrier, 1, image_barrier); + } + // Copy to Image: + { + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.width = width; + region.imageExtent.height = height; + vkCmdCopyBufferToImage(command_buffer, + g_UploadBuffer, + g_FontImage, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion); + } + // Usage Barrier: + { + VkImageMemoryBarrier image_barrier[1] = {}; + image_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + image_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + image_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + image_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + image_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + image_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + image_barrier[0].image = g_FontImage; + image_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + image_barrier[0].subresourceRange.levelCount = 1; + image_barrier[0].subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, NULL, 0, NULL, 1, image_barrier); + } + io.Fonts->TexID = (void *)(intptr_t)g_FontImage; + + io.Fonts->ClearInputData(); + io.Fonts->ClearTexData(); + + return true; +} + +bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() +{ + VkResult err; + + VkShaderModule vert_module; + VkShaderModule frag_module; + + // Create The Shader Modules: + { + VkShaderModuleCreateInfo vert_info = {}; + vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + vert_info.codeSize = __glsl_shader_vert_spv_len; + vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv; + err = vkCreateShaderModule(g_Device, &vert_info, g_Allocator, &vert_module); + ImGui_ImplGlfwVulkan_VkResult(err); + VkShaderModuleCreateInfo frag_info = {}; + frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + frag_info.codeSize = __glsl_shader_frag_spv_len; + frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv; + err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); + ImGui_ImplGlfwVulkan_VkResult(err); + } + + if(!g_FontSampler){ + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.minLod = -1000; + info.maxLod = 1000; + err = vkCreateSampler(g_Device, + &info, + g_Allocator, + &g_FontSampler); + ImGui_ImplGlfwVulkan_VkResult(err); + } + + if(!g_DescriptorSetLayout){ + VkSampler sampler[1] = {g_FontSampler}; + VkDescriptorSetLayoutBinding binding[1] = {}; + binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding[0].descriptorCount = 1; + binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + binding[0].pImmutableSamplers = sampler; + VkDescriptorSetLayoutCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.bindingCount = 1; + info.pBindings = binding; + err = vkCreateDescriptorSetLayout(g_Device, + &info, + g_Allocator, + &g_DescriptorSetLayout); + ImGui_ImplGlfwVulkan_VkResult(err); + } + { + VkDescriptorSetAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = g_DescriptorPool; + alloc_info.descriptorSetCount = 1; + alloc_info.pSetLayouts = &g_DescriptorSetLayout; + err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet); + ImGui_ImplGlfwVulkan_VkResult(err); + } + if(!g_PipelineLayout){ + VkPushConstantRange push_constants[2] = {}; + push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constants[0].offset = sizeof(float) * 0; + push_constants[0].size = sizeof(float) * 2; + push_constants[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constants[1].offset = sizeof(float) * 2; + push_constants[1].size = sizeof(float) * 2; + VkDescriptorSetLayout set_layout[1] = {g_DescriptorSetLayout}; + VkPipelineLayoutCreateInfo layout_info = {}; + layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layout_info.setLayoutCount = 1; + layout_info.pSetLayouts = set_layout; + layout_info.pushConstantRangeCount = 2; + layout_info.pPushConstantRanges = push_constants; + err = vkCreatePipelineLayout(g_Device, &layout_info, + g_Allocator, &g_PipelineLayout); + ImGui_ImplGlfwVulkan_VkResult(err); + } + + VkPipelineShaderStageCreateInfo stage[2] = {}; + stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stage[0].module = vert_module; + stage[0].pName = "main"; + stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stage[1].module = frag_module; + stage[1].pName = "main"; + + VkVertexInputBindingDescription binding_desc[1] = {}; + binding_desc[0].stride = sizeof(ImDrawVert); + binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + VkVertexInputAttributeDescription attribute_desc[3] = {}; + attribute_desc[0].location = 0; + attribute_desc[0].binding = binding_desc[0].binding; + attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; + attribute_desc[0].offset = (size_t)(&((ImDrawVert*)0)->pos); + attribute_desc[1].location = 1; + attribute_desc[1].binding = binding_desc[0].binding; + attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; + attribute_desc[1].offset = (size_t)(&((ImDrawVert*)0)->uv); + attribute_desc[2].location = 2; + attribute_desc[2].binding = binding_desc[0].binding; + attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; + attribute_desc[2].offset = (size_t)(&((ImDrawVert*)0)->col); + + VkPipelineVertexInputStateCreateInfo vertex_info = {}; + vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_info.vertexBindingDescriptionCount = 1; + vertex_info.pVertexBindingDescriptions = binding_desc; + vertex_info.vertexAttributeDescriptionCount = 3; + vertex_info.pVertexAttributeDescriptions = attribute_desc; + + VkPipelineInputAssemblyStateCreateInfo ia_info = {}; + ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineViewportStateCreateInfo viewport_info = {}; + viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_info.viewportCount = 1; + viewport_info.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo raster_info = {}; + raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + raster_info.polygonMode = VK_POLYGON_MODE_FILL; + raster_info.cullMode = VK_CULL_MODE_NONE; + raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + + VkPipelineMultisampleStateCreateInfo ms_info = {}; + ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState color_attachment[1] = {}; + color_attachment[0].blendEnable = VK_TRUE; + color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; + color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; + color_attachment[0].colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo blend_info = {}; + blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + blend_info.attachmentCount = 1; + blend_info.pAttachments = color_attachment; + + VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; + VkPipelineDynamicStateCreateInfo dynamic_state = {}; + dynamic_state.dynamicStateCount = 2; + dynamic_state.pDynamicStates = dynamic_states; + + VkGraphicsPipelineCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + info.flags = g_PipelineCreateFlags; + info.stageCount = 2; + info.pStages = stage; + info.pVertexInputState = &vertex_info; + info.pInputAssemblyState = &ia_info; + info.pViewportState = &viewport_info; + info.pRasterizationState = &raster_info; + info.pMultisampleState = &ms_info; + info.pColorBlendState = &blend_info; + info.pDynamicState = &dynamic_state; + info.layout = g_PipelineLayout; + info.renderPass = g_RenderPass; + err = vkCreateGraphicsPipelines(g_Device, + g_PipelineCache, + 1, &info, + g_Allocator, + &g_Pipeline); + ImGui_ImplGlfwVulkan_VkResult(err); + + vkDestroyShaderModule(g_Device, vert_module, g_Allocator); + vkDestroyShaderModule(g_Device, frag_module, g_Allocator); + + return true; +} + +void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects() +{ + if(g_UploadBuffer){ + vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator); + g_UploadBuffer = VK_NULL_HANDLE; + } + if(g_UploadBufferMemory){ + vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator); + g_UploadBufferMemory = VK_NULL_HANDLE; + } +} +void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects() +{ + ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); + for(int i=0; iallocator; + g_Gpu = init_data->gpu; + g_Device = init_data->device; + g_RenderPass = init_data->render_pass; + g_PipelineCache = init_data->pipeline_cache; + g_DescriptorPool = init_data->descriptor_pool; + g_CheckVkResult = init_data->check_vk_result; + + g_Window = window; + + ImGuiIO& io = ImGui::GetIO(); + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. + 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_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + 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; + + io.RenderDrawListsFn = ImGui_ImplGlfwVulkan_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. + io.SetClipboardTextFn = ImGui_ImplGlfwVulkan_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfwVulkan_GetClipboardText; +#ifdef _WIN32 + io.ImeWindowHandle = glfwGetWin32Window(g_Window); +#endif + + if (install_callbacks) + { + glfwSetMouseButtonCallback(window, ImGui_ImplGlfwVulkan_MouseButtonCallback); + glfwSetScrollCallback(window, ImGui_ImplGlfwVulkan_ScrollCallback); + glfwSetKeyCallback(window, ImGui_ImplGlfwVulkan_KeyCallback); + glfwSetCharCallback(window, ImGui_ImplGlfwVulkan_CharCallback); + } + + ImGui_ImplGlfwVulkan_CreateDeviceObjects(); + + return true; +} + +void ImGui_ImplGlfwVulkan_Shutdown() +{ + ImGui_ImplGlfwVulkan_InvalidateDeviceObjects(); + ImGui::Shutdown(); +} + +void ImGui_ImplGlfwVulkan_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + + // 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); + io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); + + // 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; + + // Setup inputs + // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) + if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED)) + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) + } + else + { + io.MousePos = ImVec2(-1,-1); + } + + for (int i = 0; i < 3; i++) + { + io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // 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. + g_MousePressed[i] = false; + } + + io.MouseWheel = g_MouseWheel; + g_MouseWheel = 0.0f; + + // Hide OS mouse cursor if ImGui is drawing it + glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); + + // Start the frame + ImGui::NewFrame(); +} +void ImGui_ImplGlfwVulkan_Render(VkCommandBuffer command_buffer) +{ + g_CommandBuffer = command_buffer; + ImGui::Render(); + g_CommandBuffer = VK_NULL_HANDLE; + g_FrameIndex = (g_FrameIndex+1)%IMGUI_VK_QUEUED_FRAMES; +} diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.h b/examples/vulkan_example/imgui_impl_glfw_vulkan.h new file mode 100644 index 000000000..3c04ed63e --- /dev/null +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.h @@ -0,0 +1,41 @@ +// ImGui GLFW binding with Vulkan + shaders +// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. +// If you use this binding you'll need to call 5 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXX_CreateFontsTexture(), ImGui_ImplXXXX_NewFrame(), ImGui_ImplXXXX_Render() and ImGui_ImplXXXX_Shutdown(). +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. +// https://github.com/ocornut/imgui + +#define IMGUI_VK_QUEUED_FRAMES 2 + +struct GLFWwindow; + +struct ImGui_ImplGlfwVulkan_Init_Data{ + VkAllocationCallbacks* allocator; + VkPhysicalDevice gpu; + VkDevice device; + VkRenderPass render_pass; + VkPipelineCache pipeline_cache; + VkDescriptorPool descriptor_pool; + void (*check_vk_result)(VkResult err); +}; + +IMGUI_API bool ImGui_ImplGlfwVulkan_Init(GLFWwindow* window, bool install_callbacks, ImGui_ImplGlfwVulkan_Init_Data *init_data); +IMGUI_API void ImGui_ImplGlfwVulkan_Shutdown(); +IMGUI_API void ImGui_ImplGlfwVulkan_NewFrame(); +IMGUI_API void ImGui_ImplGlfwVulkan_Render(VkCommandBuffer command_buffer); + +// Use if you want to reset your rendering device without losing ImGui state. +IMGUI_API void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); +IMGUI_API void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects(); +IMGUI_API bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); +IMGUI_API bool ImGui_ImplGlfwVulkan_CreateDeviceObjects(); + + +// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization) +// Provided here if you want to chain callbacks. +// You can also handle inputs yourself and use those as a reference. +IMGUI_API void ImGui_ImplGlfwVulkan_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +IMGUI_API void ImGui_ImplGlfwVulkan_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); +IMGUI_API void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +IMGUI_API void ImGui_ImplGlfwVulkan_CharCallback(GLFWwindow* window, unsigned int c); + + diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp new file mode 100644 index 000000000..c42bcdf68 --- /dev/null +++ b/examples/vulkan_example/main.cpp @@ -0,0 +1,533 @@ +// ImGui - standalone example application for Glfw + Vulkan, using programmable pipeline +// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. + +#include + +#include +#include +#define GLFW_INCLUDE_NONE +#define GLFW_INCLUDE_VULKAN +#include + +#include "imgui_impl_glfw_vulkan.h" + +#define IMGUI_MAX_POSSIBLE_BACK_BUFFERS 16 + +static VkAllocationCallbacks* g_Allocator = NULL; +static VkInstance g_Instance = VK_NULL_HANDLE; +static VkSurfaceKHR g_Surface = VK_NULL_HANDLE; +static VkPhysicalDevice g_Gpu = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static VkSwapchainKHR g_Swapchain = VK_NULL_HANDLE; +static VkRenderPass g_RenderPass = VK_NULL_HANDLE; +static uint32_t g_QueueFamily = 0; +static VkQueue g_Queue = VK_NULL_HANDLE; + +static VkFormat g_Format = VK_FORMAT_B8G8R8A8_UNORM; +static VkColorSpaceKHR g_ColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; +static VkImageSubresourceRange g_ImageRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; + +static int fb_width, fb_height; +static uint32_t g_BackBufferIndex = 0; +static uint32_t g_BackBufferCount = 0; +static VkImage g_BackBuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; +static VkImageView g_BackBufferView[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; +static VkFramebuffer g_Framebuffer[IMGUI_MAX_POSSIBLE_BACK_BUFFERS] = {}; + +static uint32_t g_FrameIndex = 0; +static VkCommandPool g_CommandPool[IMGUI_VK_QUEUED_FRAMES]; +static VkCommandBuffer g_CommandBuffer[IMGUI_VK_QUEUED_FRAMES]; +static VkFence g_Fence[IMGUI_VK_QUEUED_FRAMES]; +static VkSemaphore g_Semaphore[IMGUI_VK_QUEUED_FRAMES]; + +static VkClearValue g_ClearValue = {}; + +static void check_vk_result(VkResult err) +{ + if(err == 0) return; + printf("VkResult %d\n", err); + if(err < 0) abort(); +} + +static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) +{ + VkResult err; + VkSwapchainKHR old_swapchain = g_Swapchain; + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + // Destroy old Framebuffer: + for(uint32_t i=0; iAddFontDefault(); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/Cousine-Regular.ttf", 15.0f); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/ProggyClean.ttf", 13.0f); + //io.Fonts->AddFontFromFileTTF("../../extra_fonts/ProggyTiny.ttf", 10.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); + + // Upload Fonts + { + VkResult err; + err = vkResetCommandPool(g_Device, g_CommandPool[g_FrameIndex], 0); + check_vk_result(err); + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(g_CommandBuffer[g_FrameIndex], &begin_info); + check_vk_result(err); + + ImGui_ImplGlfwVulkan_CreateFontsTexture(g_CommandBuffer[g_FrameIndex]); + + VkSubmitInfo end_info = {}; + end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + end_info.commandBufferCount = 1; + end_info.pCommandBuffers = &g_CommandBuffer[g_FrameIndex]; + err = vkEndCommandBuffer(g_CommandBuffer[g_FrameIndex]); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &end_info, VK_NULL_HANDLE); + check_vk_result(err); + + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); + } + + bool show_test_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImColor(114, 144, 154); + + // Main loop + while (!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + ImGui_ImplGlfwVulkan_NewFrame(); + + // 1. Show a simple window + // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug" + { + static float f = 0.0f; + ImGui::Text("Hello, world!"); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + ImGui::ColorEdit3("clear color", (float*)&clear_color); + if (ImGui::Button("Test Window")) show_test_window ^= 1; + if (ImGui::Button("Another Window")) show_another_window ^= 1; + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + } + + // 2. Show another simple window, this time using an explicit Begin/End pair + if (show_another_window) + { + ImGui::SetNextWindowSize(ImVec2(200,100), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Another Window", &show_another_window); + ImGui::Text("Hello"); + ImGui::End(); + } + + // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow() + if (show_test_window) + { + ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver); + ImGui::ShowTestWindow(&show_test_window); + } + + g_ClearValue.color.float32[0] = clear_color.x; + g_ClearValue.color.float32[1] = clear_color.y; + g_ClearValue.color.float32[2] = clear_color.z; + g_ClearValue.color.float32[3] = clear_color.w; + + frame_begin(); + + ImGui_ImplGlfwVulkan_Render(g_CommandBuffer[g_FrameIndex]); + + frame_end(); + } + + // Cleanup + VkResult err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + ImGui_ImplGlfwVulkan_Shutdown(); + cleanup_vulkan(); + glfwTerminate(); + + return 0; +} From 0ceddc29ff5b80dd270b7810f6bfa931c8353e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Wed, 9 Mar 2016 17:01:38 +0100 Subject: [PATCH 02/24] Vulkan Example: Fix windows build. --- examples/vulkan_example/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/vulkan_example/CMakeLists.txt b/examples/vulkan_example/CMakeLists.txt index daa7a1716..3657c8294 100644 --- a/examples/vulkan_example/CMakeLists.txt +++ b/examples/vulkan_example/CMakeLists.txt @@ -9,7 +9,7 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES") # GLFW -set(GLFW_DIR ../../../glfw) +set(GLFW_DIR ../../../glfw) # Set this to point to a up-to-date GLFW repo option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) @@ -23,12 +23,12 @@ set(IMGUI_DIR ../../) include_directories(${IMGUI_DIR}) # Libraries -if(WIN32) - set(LIBRARIES "glfw;vulkan-${MAJOR}") -elseif(UNIX) - set(LIBRARIES "glfw;vulkan") -else() -endif() +find_library(VULKAN_LIBRARY + NAMES vulkan vulkan-1) +set(LIBRARIES "glfw;${VULKAN_LIBRARY}") + +# Use vulkan headers from glfw: +include_directories(${GLFW_DIR}/deps) file(GLOB sources *.cpp) From 4ea4fa3e7318af552c5ea8fd36360babcb51c9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Thu, 10 Mar 2016 11:59:42 +0100 Subject: [PATCH 03/24] Vulkan Example: Fix synchronization. --- examples/vulkan_example/imgui_impl_glfw_vulkan.cpp | 10 +--------- examples/vulkan_example/main.cpp | 8 -------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 7ca1ab9fa..ae4790563 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -605,14 +605,6 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) } // Upload Barrier: { - VkBufferMemoryBarrier buffer_barrier[1] = {}; - buffer_barrier[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - buffer_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; - buffer_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - buffer_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - buffer_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - buffer_barrier[0].buffer = g_UploadBuffer; - buffer_barrier[0].size = upload_size; VkImageMemoryBarrier image_barrier[1] = {}; image_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -628,7 +620,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, NULL, 1, buffer_barrier, 1, image_barrier); + 0, NULL, 0, NULL, 1, image_barrier); } // Copy to Image: { diff --git a/examples/vulkan_example/main.cpp b/examples/vulkan_example/main.cpp index c42bcdf68..293f0557d 100644 --- a/examples/vulkan_example/main.cpp +++ b/examples/vulkan_example/main.cpp @@ -311,14 +311,6 @@ static void frame_begin() if(err == VK_TIMEOUT) continue; check_vk_result(err); } - { - vkDestroySemaphore(g_Device, g_Semaphore[g_FrameIndex], g_Allocator); - VkSemaphoreCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - err = vkCreateSemaphore(g_Device, &info, g_Allocator, - &g_Semaphore[g_FrameIndex]); - check_vk_result(err); - } { err = vkAcquireNextImageKHR( g_Device, g_Swapchain, From 1394616d9c87114d5c84b1deb6d75a58dc82d504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Mathisen?= Date: Thu, 10 Mar 2016 12:30:38 +0100 Subject: [PATCH 04/24] Vulkan Example: Some code layout changes. --- .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index ae4790563..4774f173f 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -228,7 +228,7 @@ static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties if((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<TexID = (void *)(intptr_t)g_FontImage; @@ -685,7 +679,6 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_FontSampler){ VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -703,7 +696,6 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() &g_FontSampler); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_DescriptorSetLayout){ VkSampler sampler[1] = {g_FontSampler}; VkDescriptorSetLayoutBinding binding[1] = {}; @@ -721,6 +713,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() &g_DescriptorSetLayout); ImGui_ImplGlfwVulkan_VkResult(err); } + // Create Descriptor Set: { VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; From d4d51a78027fa9e44da46fc712d05216a8d0186a Mon Sep 17 00:00:00 2001 From: Nicolas Guillemot Date: Sat, 2 Apr 2016 19:08:27 -0700 Subject: [PATCH 05/24] capture and restore all state --- .../directx11_example/imgui_impl_dx11.cpp | 68 ++++++++++++++++++- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 8451fb8eb..4ca652019 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -116,6 +116,46 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); } + // Capture all the state that will be modified to restore it afterwards + UINT oldNumScissorRects = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + D3D11_RECT oldScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + g_pd3dDeviceContext->RSGetScissorRects(&oldNumScissorRects, oldScissorRects); + ID3D11ShaderResourceView* pOldPSSRV0; + g_pd3dDeviceContext->PSGetShaderResources(0, 1, &pOldPSSRV0); + ID3D11RasterizerState* pOldRS; + g_pd3dDeviceContext->RSGetState(&pOldRS); + ID3D11BlendState* pOldBlendState; + FLOAT oldBlendFactor[4]; + UINT oldSampleMask; + g_pd3dDeviceContext->OMGetBlendState(&pOldBlendState, oldBlendFactor, &oldSampleMask); + ID3D11SamplerState* pOldPSSampler; + g_pd3dDeviceContext->PSGetSamplers(0, 1, &pOldPSSampler); + ID3D11PixelShader* pOldPS; + ID3D11ClassInstance* pOldPSInstances[256]; // max according to PSSetShader documentation + UINT oldNumPSInstances = 256; + g_pd3dDeviceContext->PSGetShader(&pOldPS, pOldPSInstances, &oldNumPSInstances); + ID3D11Buffer* pOldVSCBV; + g_pd3dDeviceContext->VSGetConstantBuffers(0, 1, &pOldVSCBV); + ID3D11VertexShader* pOldVS; + ID3D11ClassInstance* pOldVSInstances[256]; // max according to VSSetShader documentation + UINT oldNumVSInstances = 256; + g_pd3dDeviceContext->VSGetShader(&pOldVS, pOldVSInstances, &oldNumVSInstances); + D3D11_PRIMITIVE_TOPOLOGY oldPrimitiveTopology; + g_pd3dDeviceContext->IAGetPrimitiveTopology(&oldPrimitiveTopology); + ID3D11Buffer* pOldIndexBuffer; + DXGI_FORMAT oldIndexBufferFormat; + UINT oldIndexBufferOffset; + g_pd3dDeviceContext->IAGetIndexBuffer(&pOldIndexBuffer, &oldIndexBufferFormat, &oldIndexBufferOffset); + ID3D11Buffer* pOldVertexBuffer; + UINT oldVertexBufferStride; + UINT oldVertexBufferOffset; + g_pd3dDeviceContext->IAGetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); + ID3D11InputLayout* pOldInputLayout; + g_pd3dDeviceContext->IAGetInputLayout(&pOldInputLayout); + UINT oldNumViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + D3D11_VIEWPORT oldViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + g_pd3dDeviceContext->RSGetViewports(&oldNumViewports, oldViewports); + // Setup viewport { D3D11_VIEWPORT vp; @@ -172,9 +212,31 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) } // Restore modified state - g_pd3dDeviceContext->IASetInputLayout(NULL); - g_pd3dDeviceContext->PSSetShader(NULL, NULL, 0); - g_pd3dDeviceContext->VSSetShader(NULL, NULL, 0); + g_pd3dDeviceContext->RSSetScissorRects(oldNumScissorRects, oldScissorRects); + g_pd3dDeviceContext->PSSetShaderResources(0, 1, &pOldPSSRV0); + if (pOldPSSRV0) pOldPSSRV0->Release(); + g_pd3dDeviceContext->RSSetState(pOldRS); + if (pOldRS) pOldRS->Release(); + g_pd3dDeviceContext->OMSetBlendState(pOldBlendState, oldBlendFactor, oldSampleMask); + if (pOldBlendState) pOldBlendState->Release(); + g_pd3dDeviceContext->PSSetSamplers(0, 1, &pOldPSSampler); + if (pOldPSSampler) pOldPSSampler->Release(); + g_pd3dDeviceContext->PSSetShader(pOldPS, pOldPSInstances, oldNumPSInstances); + if (pOldPS) pOldPS->Release(); + for (UINT i = 0; i < oldNumPSInstances; i++) if (pOldPSInstances[i]) pOldPSInstances[i]->Release(); + g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &pOldVSCBV); + if (pOldVSCBV) pOldVSCBV->Release(); + g_pd3dDeviceContext->VSSetShader(pOldVS, pOldVSInstances, oldNumVSInstances); + if (pOldVS) pOldVS->Release(); + for (UINT i = 0; i < oldNumVSInstances; i++) if (pOldVSInstances[i]) pOldVSInstances[i]->Release(); + g_pd3dDeviceContext->IASetPrimitiveTopology(oldPrimitiveTopology); + g_pd3dDeviceContext->IASetIndexBuffer(pOldIndexBuffer, oldIndexBufferFormat, oldIndexBufferOffset); + if (pOldIndexBuffer) pOldIndexBuffer->Release(); + g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); + if (pOldVertexBuffer) pOldVertexBuffer->Release(); + g_pd3dDeviceContext->IASetInputLayout(pOldInputLayout); + if (pOldInputLayout) pOldInputLayout->Release(); + g_pd3dDeviceContext->RSSetViewports(oldNumViewports, oldViewports); } IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 2942240072c8b16387333ad313a80ab30e9ef6a4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 12:43:17 +0200 Subject: [PATCH 06/24] Examples: DX11: Cleanup state backup/restore code (#570) --- .../directx11_example/imgui_impl_dx11.cpp | 120 ++++++++---------- 1 file changed, 55 insertions(+), 65 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 4ca652019..bc6a0858e 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -116,45 +116,45 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); } - // Capture all the state that will be modified to restore it afterwards - UINT oldNumScissorRects = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - D3D11_RECT oldScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; - g_pd3dDeviceContext->RSGetScissorRects(&oldNumScissorRects, oldScissorRects); - ID3D11ShaderResourceView* pOldPSSRV0; - g_pd3dDeviceContext->PSGetShaderResources(0, 1, &pOldPSSRV0); - ID3D11RasterizerState* pOldRS; - g_pd3dDeviceContext->RSGetState(&pOldRS); - ID3D11BlendState* pOldBlendState; - FLOAT oldBlendFactor[4]; - UINT oldSampleMask; - g_pd3dDeviceContext->OMGetBlendState(&pOldBlendState, oldBlendFactor, &oldSampleMask); - ID3D11SamplerState* pOldPSSampler; - g_pd3dDeviceContext->PSGetSamplers(0, 1, &pOldPSSampler); - ID3D11PixelShader* pOldPS; - ID3D11ClassInstance* pOldPSInstances[256]; // max according to PSSetShader documentation - UINT oldNumPSInstances = 256; - g_pd3dDeviceContext->PSGetShader(&pOldPS, pOldPSInstances, &oldNumPSInstances); - ID3D11Buffer* pOldVSCBV; - g_pd3dDeviceContext->VSGetConstantBuffers(0, 1, &pOldVSCBV); - ID3D11VertexShader* pOldVS; - ID3D11ClassInstance* pOldVSInstances[256]; // max according to VSSetShader documentation - UINT oldNumVSInstances = 256; - g_pd3dDeviceContext->VSGetShader(&pOldVS, pOldVSInstances, &oldNumVSInstances); - D3D11_PRIMITIVE_TOPOLOGY oldPrimitiveTopology; - g_pd3dDeviceContext->IAGetPrimitiveTopology(&oldPrimitiveTopology); - ID3D11Buffer* pOldIndexBuffer; - DXGI_FORMAT oldIndexBufferFormat; - UINT oldIndexBufferOffset; - g_pd3dDeviceContext->IAGetIndexBuffer(&pOldIndexBuffer, &oldIndexBufferFormat, &oldIndexBufferOffset); - ID3D11Buffer* pOldVertexBuffer; - UINT oldVertexBufferStride; - UINT oldVertexBufferOffset; - g_pd3dDeviceContext->IAGetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); - ID3D11InputLayout* pOldInputLayout; - g_pd3dDeviceContext->IAGetInputLayout(&pOldInputLayout); - UINT oldNumViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - D3D11_VIEWPORT oldViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; - g_pd3dDeviceContext->RSGetViewports(&oldNumViewports, oldViewports); + // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) + ID3D11DeviceContext* ctx = g_pd3dDeviceContext; + 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; + 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->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 viewport { @@ -211,32 +211,22 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) vtx_offset += cmd_list->VtxBuffer.size(); } - // Restore modified state - g_pd3dDeviceContext->RSSetScissorRects(oldNumScissorRects, oldScissorRects); - g_pd3dDeviceContext->PSSetShaderResources(0, 1, &pOldPSSRV0); - if (pOldPSSRV0) pOldPSSRV0->Release(); - g_pd3dDeviceContext->RSSetState(pOldRS); - if (pOldRS) pOldRS->Release(); - g_pd3dDeviceContext->OMSetBlendState(pOldBlendState, oldBlendFactor, oldSampleMask); - if (pOldBlendState) pOldBlendState->Release(); - g_pd3dDeviceContext->PSSetSamplers(0, 1, &pOldPSSampler); - if (pOldPSSampler) pOldPSSampler->Release(); - g_pd3dDeviceContext->PSSetShader(pOldPS, pOldPSInstances, oldNumPSInstances); - if (pOldPS) pOldPS->Release(); - for (UINT i = 0; i < oldNumPSInstances; i++) if (pOldPSInstances[i]) pOldPSInstances[i]->Release(); - g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &pOldVSCBV); - if (pOldVSCBV) pOldVSCBV->Release(); - g_pd3dDeviceContext->VSSetShader(pOldVS, pOldVSInstances, oldNumVSInstances); - if (pOldVS) pOldVS->Release(); - for (UINT i = 0; i < oldNumVSInstances; i++) if (pOldVSInstances[i]) pOldVSInstances[i]->Release(); - g_pd3dDeviceContext->IASetPrimitiveTopology(oldPrimitiveTopology); - g_pd3dDeviceContext->IASetIndexBuffer(pOldIndexBuffer, oldIndexBufferFormat, oldIndexBufferOffset); - if (pOldIndexBuffer) pOldIndexBuffer->Release(); - g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &pOldVertexBuffer, &oldVertexBufferStride, &oldVertexBufferOffset); - if (pOldVertexBuffer) pOldVertexBuffer->Release(); - g_pd3dDeviceContext->IASetInputLayout(pOldInputLayout); - if (pOldInputLayout) pOldInputLayout->Release(); - g_pd3dDeviceContext->RSSetViewports(oldNumViewports, oldViewports); + // 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->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(); } IMGUI_API LRESULT ImGui_ImplDX11_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 90493f8add46738278d8b60ba9131d3673057c74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 12:48:38 +0200 Subject: [PATCH 07/24] Examples: DirectX11: Shallow massaging to make the code more consistent/readable (following #570) --- .../directx11_example/imgui_impl_dx11.cpp | 93 +++++++++---------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index bc6a0858e..f02da1299 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -46,6 +46,8 @@ struct VERTEX_CONSTANT_BUFFER // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { + ID3D11DeviceContext* ctx = g_pd3dDeviceContext; + // Create and grow vertex/index buffers if needed if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) { @@ -65,21 +67,21 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D11_BUFFER_DESC bufferDesc; - memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); - bufferDesc.Usage = D3D11_USAGE_DYNAMIC; - bufferDesc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pIB) < 0) + D3D11_BUFFER_DESC buffer_desc; + memset(&buffer_desc, 0, sizeof(D3D11_BUFFER_DESC)); + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); + buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + if (g_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &g_pIB) < 0) return; } // Copy and convert all vertices into a single contiguous buffer D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; - if (g_pd3dDeviceContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) + if (ctx->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) return; - if (g_pd3dDeviceContext->Map(g_pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) + 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; @@ -91,33 +93,31 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) vtx_dst += cmd_list->VtxBuffer.size(); idx_dst += cmd_list->IdxBuffer.size(); } - g_pd3dDeviceContext->Unmap(g_pVB, 0); - g_pd3dDeviceContext->Unmap(g_pIB, 0); + ctx->Unmap(g_pVB, 0); + ctx->Unmap(g_pIB, 0); // Setup orthographic projection matrix into our constant buffer { - D3D11_MAPPED_SUBRESOURCE mappedResource; - if (g_pd3dDeviceContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) + D3D11_MAPPED_SUBRESOURCE mapped_resource; + if (ctx->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) return; - - VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData; - const float L = 0.0f; - const float R = ImGui::GetIO().DisplaySize.x; - const float B = ImGui::GetIO().DisplaySize.y; - const float T = 0.0f; - const float mvp[4][4] = + VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource.pData; + float L = 0.0f; + float R = ImGui::GetIO().DisplaySize.x; + float B = ImGui::GetIO().DisplaySize.y; + float T = 0.0f; + 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(&pConstantBuffer->mvp, mvp, sizeof(mvp)); - g_pd3dDeviceContext->Unmap(g_pVertexConstantBuffer, 0); + 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!) - ID3D11DeviceContext* ctx = g_pd3dDeviceContext; struct BACKUP_DX11_STATE { UINT ScissorRectsCount, ViewportsCount; @@ -157,34 +157,31 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) ctx->IAGetInputLayout(&old.InputLayout); // Setup viewport - { - D3D11_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D11_VIEWPORT)); - vp.Width = ImGui::GetIO().DisplaySize.x; - vp.Height = ImGui::GetIO().DisplaySize.y; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - g_pd3dDeviceContext->RSSetViewports(1, &vp); - } + D3D11_VIEWPORT vp; + memset(&vp, 0, sizeof(D3D11_VIEWPORT)); + vp.Width = ImGui::GetIO().DisplaySize.x; + vp.Height = ImGui::GetIO().DisplaySize.y; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = vp.TopLeftY = 0.0f; + ctx->RSSetViewports(1, &vp); // Bind shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; - g_pd3dDeviceContext->IASetInputLayout(g_pInputLayout); - g_pd3dDeviceContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); - g_pd3dDeviceContext->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); - g_pd3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - g_pd3dDeviceContext->VSSetShader(g_pVertexShader, NULL, 0); - g_pd3dDeviceContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); - g_pd3dDeviceContext->PSSetShader(g_pPixelShader, NULL, 0); - g_pd3dDeviceContext->PSSetSamplers(0, 1, &g_pFontSampler); + 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 render state - const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; - g_pd3dDeviceContext->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff); - g_pd3dDeviceContext->RSSetState(g_pRasterizerState); + const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; + ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->RSSetState(g_pRasterizerState); // Render command lists int vtx_offset = 0; @@ -202,9 +199,9 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) else { const D3D11_RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; - g_pd3dDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId); - g_pd3dDeviceContext->RSSetScissorRects(1, &r); - g_pd3dDeviceContext->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); + ctx->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView**)&pcmd->TextureId); + ctx->RSSetScissorRects(1, &r); + ctx->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); } idx_offset += pcmd->ElemCount; } From 518f32ccfeab5d2c71e072c136ed305434aa9fea Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 12:59:56 +0200 Subject: [PATCH 08/24] Examples: DirectX10: Save/restore state + minor cleanups (#570) --- .../directx10_example/imgui_impl_dx10.cpp | 129 ++++++++++++------ 1 file changed, 86 insertions(+), 43 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 21f86f5d8..3afe289ad 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -46,6 +46,8 @@ struct VERTEX_CONSTANT_BUFFER // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) { + ID3D10Device* ctx = g_pd3dDevice; + // Create and grow vertex/index buffers if needed if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) { @@ -58,7 +60,7 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; desc.MiscFlags = 0; - if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0) + if (ctx->CreateBuffer(&desc, NULL, &g_pVB) < 0) return; } @@ -66,13 +68,13 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D10_BUFFER_DESC bufferDesc; - memset(&bufferDesc, 0, sizeof(D3D10_BUFFER_DESC)); - bufferDesc.Usage = D3D10_USAGE_DYNAMIC; - bufferDesc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); - bufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER; - bufferDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pIB) < 0) + D3D10_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); + desc.BindFlags = D3D10_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + if (ctx->CreateBuffer(&desc, NULL, &g_pIB) < 0) return; } @@ -81,7 +83,6 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) ImDrawIdx* idx_dst = NULL; g_pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst); g_pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst); - for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; @@ -95,11 +96,10 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) // Setup orthographic projection matrix into our constant buffer { - void* mappedResource; - if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK) + void* mapped_resource; + if (g_pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) return; - - VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource; + VERTEX_CONSTANT_BUFFER* constant_buffer = (VERTEX_CONSTANT_BUFFER*)mapped_resource; const float L = 0.0f; const float R = ImGui::GetIO().DisplaySize.x; const float B = ImGui::GetIO().DisplaySize.y; @@ -111,39 +111,72 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) { 0.0f, 0.0f, 0.5f, 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, }; - memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp)); + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); g_pVertexConstantBuffer->Unmap(); } - // Setup viewport + // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) + struct BACKUP_DX10_STATE { - D3D10_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D10_VIEWPORT)); - vp.Width = (UINT)ImGui::GetIO().DisplaySize.x; - vp.Height = (UINT)ImGui::GetIO().DisplaySize.y; - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - g_pd3dDevice->RSSetViewports(1, &vp); - } + UINT ScissorRectsCount, ViewportsCount; + D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + ID3D10RasterizerState* RS; + ID3D10BlendState* BlendState; + FLOAT BlendFactor[4]; + UINT SampleMask; + ID3D10ShaderResourceView* PSShaderResource; + ID3D10SamplerState* PSSampler; + ID3D10PixelShader* PS; + ID3D10VertexShader* VS; + D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology; + ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; + UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; + DXGI_FORMAT IndexBufferFormat; + ID3D10InputLayout* InputLayout; + }; + BACKUP_DX10_STATE old; + old.ScissorRectsCount = old.ViewportsCount = D3D10_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->PSGetShaderResources(0, 1, &old.PSShaderResource); + ctx->PSGetSamplers(0, 1, &old.PSSampler); + ctx->PSGetShader(&old.PS); + ctx->VSGetShader(&old.VS); + 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 viewport + D3D10_VIEWPORT vp; + memset(&vp, 0, sizeof(D3D10_VIEWPORT)); + vp.Width = (UINT)ImGui::GetIO().DisplaySize.x; + vp.Height = (UINT)ImGui::GetIO().DisplaySize.y; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = vp.TopLeftY = 0; + ctx->RSSetViewports(1, &vp); // Bind shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; - g_pd3dDevice->IASetInputLayout(g_pInputLayout); - g_pd3dDevice->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset); - g_pd3dDevice->IASetIndexBuffer(g_pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); - g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - g_pd3dDevice->VSSetShader(g_pVertexShader); - g_pd3dDevice->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); - g_pd3dDevice->PSSetShader(g_pPixelShader); - g_pd3dDevice->PSSetSamplers(0, 1, &g_pFontSampler); + 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(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->VSSetShader(g_pVertexShader); + ctx->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer); + ctx->PSSetShader(g_pPixelShader); + ctx->PSSetSamplers(0, 1, &g_pFontSampler); // Setup render state - const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; - g_pd3dDevice->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff); - g_pd3dDevice->RSSetState(g_pRasterizerState); + const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; + ctx->OMSetBlendState(g_pBlendState, blend_factor, 0xffffffff); + ctx->RSSetState(g_pRasterizerState); // Render command lists int vtx_offset = 0; @@ -161,19 +194,29 @@ void ImGui_ImplDX10_RenderDrawLists(ImDrawData* draw_data) else { const D3D10_RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; - g_pd3dDevice->PSSetShaderResources(0, 1, (ID3D10ShaderResourceView**)&pcmd->TextureId); - g_pd3dDevice->RSSetScissorRects(1, &r); - g_pd3dDevice->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); + ctx->PSSetShaderResources(0, 1, (ID3D10ShaderResourceView**)&pcmd->TextureId); + ctx->RSSetScissorRects(1, &r); + ctx->DrawIndexed(pcmd->ElemCount, idx_offset, vtx_offset); } idx_offset += pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.size(); } - // Restore modified state - g_pd3dDevice->IASetInputLayout(NULL); - g_pd3dDevice->PSSetShader(NULL); - g_pd3dDevice->VSSetShader(NULL); + // 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->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); if (old.PS) old.PS->Release(); + ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release(); + ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->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(); } IMGUI_API LRESULT ImGui_ImplDX10_WndProcHandler(HWND, UINT msg, WPARAM wParam, LPARAM lParam) From 552246feed953887b1035fe4ed7d4c4290144068 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 13:02:04 +0200 Subject: [PATCH 09/24] Examples: DirectX10,DirectX11 : Minor renaming --- .../directx10_example/imgui_impl_dx10.cpp | 82 +++++++++--------- .../directx11_example/imgui_impl_dx11.cpp | 83 +++++++++---------- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 3afe289ad..f0e57f721 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -277,33 +277,33 @@ static void ImGui_ImplDX10_CreateFontsTexture() // Create DX10 texture { - D3D10_TEXTURE2D_DESC texDesc; - ZeroMemory(&texDesc, sizeof(texDesc)); - texDesc.Width = width; - texDesc.Height = height; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - texDesc.SampleDesc.Count = 1; - texDesc.Usage = D3D10_USAGE_DEFAULT; - texDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE; - texDesc.CPUAccessFlags = 0; + D3D10_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.Usage = D3D10_USAGE_DEFAULT; + desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; ID3D10Texture2D *pTexture = NULL; D3D10_SUBRESOURCE_DATA subResource; subResource.pSysMem = pixels; - subResource.SysMemPitch = texDesc.Width * 4; + subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); + g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); // Create texture view - D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc; - ZeroMemory(&srvDesc, sizeof(srvDesc)); - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = texDesc.MipLevels; - srvDesc.Texture2D.MostDetailedMip = 0; - g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView); + D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; + ZeroMemory(&srv_desc, sizeof(srv_desc)); + srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; + srv_desc.Texture2D.MipLevels = desc.MipLevels; + srv_desc.Texture2D.MostDetailedMip = 0; + g_pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &g_pFontTextureView); pTexture->Release(); } @@ -312,17 +312,17 @@ static void ImGui_ImplDX10_CreateFontsTexture() // Create texture sampler { - D3D10_SAMPLER_DESC samplerDesc; - ZeroMemory(&samplerDesc, sizeof(samplerDesc)); - samplerDesc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP; - samplerDesc.MipLODBias = 0.f; - samplerDesc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; - samplerDesc.MinLOD = 0.f; - samplerDesc.MaxLOD = 0.f; - g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); + D3D10_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler); } // Cleanup (don't clear the input data if you want to append new fonts later) @@ -374,24 +374,24 @@ bool ImGui_ImplDX10_CreateDeviceObjects() return false; // Create the input layout - D3D10_INPUT_ELEMENT_DESC localLayout[] = { + D3D10_INPUT_ELEMENT_DESC local_layout[] = + { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->pos), D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((ImDrawVert*)0)->uv), D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((ImDrawVert*)0)->col), D3D10_INPUT_PER_VERTEX_DATA, 0 }, }; - - if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) + if (g_pd3dDevice->CreateInputLayout(local_layout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) return false; // Create the constant buffer { - D3D10_BUFFER_DESC cbDesc; - cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); - cbDesc.Usage = D3D10_USAGE_DYNAMIC; - cbDesc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - cbDesc.MiscFlags = 0; - g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer); + D3D10_BUFFER_DESC desc; + desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVertexConstantBuffer); } } diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index f02da1299..5f209bc04 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -67,13 +67,13 @@ void ImGui_ImplDX11_RenderDrawLists(ImDrawData* draw_data) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D11_BUFFER_DESC buffer_desc; - memset(&buffer_desc, 0, sizeof(D3D11_BUFFER_DESC)); - buffer_desc.Usage = D3D11_USAGE_DYNAMIC; - buffer_desc.ByteWidth = g_IndexBufferSize * sizeof(ImDrawIdx); - buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; - buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - if (g_pd3dDevice->CreateBuffer(&buffer_desc, NULL, &g_pIB) < 0) + 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; } @@ -283,31 +283,31 @@ static void ImGui_ImplDX11_CreateFontsTexture() // Upload texture to graphics system { - D3D11_TEXTURE2D_DESC texDesc; - ZeroMemory(&texDesc, sizeof(texDesc)); - texDesc.Width = width; - texDesc.Height = height; - texDesc.MipLevels = 1; - texDesc.ArraySize = 1; - texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - texDesc.SampleDesc.Count = 1; - texDesc.Usage = D3D11_USAGE_DEFAULT; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - texDesc.CPUAccessFlags = 0; + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Width = width; + desc.Height = 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; ID3D11Texture2D *pTexture = NULL; D3D11_SUBRESOURCE_DATA subResource; subResource.pSysMem = pixels; - subResource.SysMemPitch = texDesc.Width * 4; + subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - g_pd3dDevice->CreateTexture2D(&texDesc, &subResource, &pTexture); + g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); // Create texture view D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; ZeroMemory(&srvDesc, sizeof(srvDesc)); srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = texDesc.MipLevels; + srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &g_pFontTextureView); pTexture->Release(); @@ -318,17 +318,17 @@ static void ImGui_ImplDX11_CreateFontsTexture() // Create texture sampler { - D3D11_SAMPLER_DESC samplerDesc; - ZeroMemory(&samplerDesc, sizeof(samplerDesc)); - samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - samplerDesc.MipLODBias = 0.f; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - samplerDesc.MinLOD = 0.f; - samplerDesc.MaxLOD = 0.f; - g_pd3dDevice->CreateSamplerState(&samplerDesc, &g_pFontSampler); + 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); } } @@ -376,24 +376,23 @@ bool ImGui_ImplDX11_CreateDeviceObjects() return false; // Create the input layout - D3D11_INPUT_ELEMENT_DESC localLayout[] = { + 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(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK) + 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 cbDesc; - cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER); - cbDesc.Usage = D3D11_USAGE_DYNAMIC; - cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - cbDesc.MiscFlags = 0; - g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer); + 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); } } From f45fd1cef67482ca326a6be6ec8cb64d76867641 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 16:42:35 +0200 Subject: [PATCH 10/24] Comments --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 1a21e1d06..f170b1666 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -504,6 +504,7 @@ - color: add a better color picker (#346) - node/graph editor (#306) - pie menus patterns (#434) + - drag'n drop, dragging helpers (carry dragging info, visualize drag source before clicking, drop target, etc.) (#143, #479) - plot: PlotLines() should use the polygon-stroke facilities (currently issues with averaging normals) - plot: make it easier for user to draw extra stuff into the graph (e.g: draw basis, highlight certain points, 2d plots, multiple plots) - plot: "smooth" automatic scale over time, user give an input 0.0(full user scale) 1.0(full derived from value) From 0e7b9b8284ad0cc52f31e4021334825c4220a079 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 3 Apr 2016 17:32:53 +0200 Subject: [PATCH 11/24] Examples: Vulkan: Coding style tweaks. --- examples/README.txt | 6 +- examples/vulkan_example/build_win32.bat | 4 + .../vulkan_example/imgui_impl_glfw_vulkan.cpp | 293 +++++++----------- .../vulkan_example/imgui_impl_glfw_vulkan.h | 9 +- examples/vulkan_example/main.cpp | 110 ++++--- 5 files changed, 188 insertions(+), 234 deletions(-) create mode 100644 examples/vulkan_example/build_win32.bat diff --git a/examples/README.txt b/examples/README.txt index f8e0c55ed..0259ae64a 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -79,4 +79,8 @@ allegro5_example/ marmalade_example/ Marmalade example using IwGx - + +vulkan_example/ + Vulkan example. + This is quite long and tedious, because: Vulkan. + diff --git a/examples/vulkan_example/build_win32.bat b/examples/vulkan_example/build_win32.bat new file mode 100644 index 000000000..e8b5a6c7a --- /dev/null +++ b/examples/vulkan_example/build_win32.bat @@ -0,0 +1,4 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +mkdir Debug +cl /nologo /Zi /MD /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\*.cpp /FeDebug/vulkan_example.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\bin32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib + diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 4774f173f..33d8e9971 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -59,7 +59,8 @@ static VkBuffer g_IndexBuffer[IMGUI_VK_QUEUED_FRAMES] = {}; static VkDeviceMemory g_UploadBufferMemory = VK_NULL_HANDLE; static VkBuffer g_UploadBuffer = VK_NULL_HANDLE; -static unsigned char __glsl_shader_vert_spv[] = { +static unsigned char __glsl_shader_vert_spv[] = +{ 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x6c, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, @@ -161,7 +162,8 @@ static unsigned char __glsl_shader_vert_spv[] = { }; static unsigned int __glsl_shader_vert_spv_len = 1172; -static unsigned char __glsl_shader_frag_spv[] = { +static unsigned char __glsl_shader_frag_spv[] = +{ 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x6c, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -224,15 +226,15 @@ static uint32_t ImGui_ImplGlfwVulkan_MemoryType(VkMemoryPropertyFlags properties { VkPhysicalDeviceMemoryProperties prop; vkGetPhysicalDeviceMemoryProperties(g_Gpu, &prop); - for(uint32_t i=0; i < prop.memoryTypeCount; ++i) - if((prop.memoryTypes[i].propertyFlags & properties) == properties && - type_bits & (1<TotalVtxCount * sizeof(ImDrawVert); - if(!g_VertexBuffer[g_FrameIndex] || - g_VertexBufferSize[g_FrameIndex] < vertex_size){ - if(g_VertexBuffer[g_FrameIndex]) + if (!g_VertexBuffer[g_FrameIndex] || g_VertexBufferSize[g_FrameIndex] < vertex_size) + { + if (g_VertexBuffer[g_FrameIndex]) vkDestroyBuffer(g_Device, g_VertexBuffer[g_FrameIndex], g_Allocator); - if(g_VertexBufferMemory[g_FrameIndex]) + if (g_VertexBufferMemory[g_FrameIndex]) vkFreeMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], g_Allocator); - size_t vertex_buffer_size = ((vertex_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + size_t vertex_buffer_size = ((vertex_size-1) / g_BufferMemoryAlignment+1) * g_BufferMemoryAlignment; VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = vertex_buffer_size; buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(g_Device, - &buffer_info, - g_Allocator, - &g_VertexBuffer[g_FrameIndex]); + err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_VertexBuffer[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_VertexBuffer[g_FrameIndex], &req); @@ -267,38 +266,29 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_VertexBufferMemory[g_FrameIndex]); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_VertexBufferMemory[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); - err = vkBindBufferMemory(g_Device, - g_VertexBuffer[g_FrameIndex], - g_VertexBufferMemory[g_FrameIndex], 0); + err = vkBindBufferMemory(g_Device, g_VertexBuffer[g_FrameIndex], g_VertexBufferMemory[g_FrameIndex], 0); ImGui_ImplGlfwVulkan_VkResult(err); g_VertexBufferSize[g_FrameIndex] = vertex_buffer_size; } + // Create the Index Buffer: size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - if(!g_IndexBuffer[g_FrameIndex] || - g_IndexBufferSize[g_FrameIndex] < index_size){ - if(g_IndexBuffer[g_FrameIndex]) + if (!g_IndexBuffer[g_FrameIndex] || g_IndexBufferSize[g_FrameIndex] < index_size) + { + if (g_IndexBuffer[g_FrameIndex]) vkDestroyBuffer(g_Device, g_IndexBuffer[g_FrameIndex], g_Allocator); - if(g_IndexBufferMemory[g_FrameIndex]) + if (g_IndexBufferMemory[g_FrameIndex]) vkFreeMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], g_Allocator); - size_t index_buffer_size = ((index_size-1)/g_BufferMemoryAlignment+1)*g_BufferMemoryAlignment; + size_t index_buffer_size = ((index_size-1) / g_BufferMemoryAlignment+1) * g_BufferMemoryAlignment; VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = index_buffer_size; buffer_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(g_Device, - &buffer_info, - g_Allocator, - &g_IndexBuffer[g_FrameIndex]); + err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_IndexBuffer[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_IndexBuffer[g_FrameIndex], &req); @@ -306,38 +296,27 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_IndexBufferMemory[g_FrameIndex]); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_IndexBufferMemory[g_FrameIndex]); ImGui_ImplGlfwVulkan_VkResult(err); - err = vkBindBufferMemory(g_Device, - g_IndexBuffer[g_FrameIndex], - g_IndexBufferMemory[g_FrameIndex], 0); + err = vkBindBufferMemory(g_Device, g_IndexBuffer[g_FrameIndex], g_IndexBufferMemory[g_FrameIndex], 0); ImGui_ImplGlfwVulkan_VkResult(err); g_IndexBufferSize[g_FrameIndex] = index_buffer_size; } + // Upload Vertex and index Data: { ImDrawVert* vtx_dst; ImDrawIdx* idx_dst; - err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], - 0, vertex_size, 0, - reinterpret_cast(&vtx_dst)); + err = vkMapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex], 0, vertex_size, 0, (void**)(&vtx_dst)); ImGui_ImplGlfwVulkan_VkResult(err); - err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], - 0, index_size, 0, - reinterpret_cast(&idx_dst)); + err = vkMapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex], 0, index_size, 0, (void**)(&idx_dst)); ImGui_ImplGlfwVulkan_VkResult(err); - for(int n = 0; n < draw_data->CmdListsCount; n++){ + for (int n = 0; n < draw_data->CmdListsCount; n++) + { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, &cmd_list->VtxBuffer[0], - cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); - memcpy(idx_dst, &cmd_list->IdxBuffer[0], - cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); + memcpy(vtx_dst, &cmd_list->VtxBuffer[0], cmd_list->VtxBuffer.size() * sizeof(ImDrawVert)); + memcpy(idx_dst, &cmd_list->IdxBuffer[0], cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx)); vtx_dst += cmd_list->VtxBuffer.size(); idx_dst += cmd_list->IdxBuffer.size(); } @@ -353,29 +332,22 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) vkUnmapMemory(g_Device, g_VertexBufferMemory[g_FrameIndex]); vkUnmapMemory(g_Device, g_IndexBufferMemory[g_FrameIndex]); } + // Bind pipeline and descriptor sets: { - vkCmdBindPipeline(g_CommandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - g_Pipeline); + vkCmdBindPipeline(g_CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline); VkDescriptorSet desc_set[1] = {g_DescriptorSet}; - vkCmdBindDescriptorSets(g_CommandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - g_PipelineLayout, - 0, 1, desc_set, - 0, NULL); + vkCmdBindDescriptorSets(g_CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL); } + // Bind Vertex And Index Buffer: { VkBuffer vertex_buffers[1] = {g_VertexBuffer[g_FrameIndex]}; VkDeviceSize vertex_offset[1] = {0}; - vkCmdBindVertexBuffers(g_CommandBuffer, - 0, 1, - vertex_buffers, vertex_offset); - vkCmdBindIndexBuffer(g_CommandBuffer, - g_IndexBuffer[g_FrameIndex], - 0, VK_INDEX_TYPE_UINT16); + vkCmdBindVertexBuffers(g_CommandBuffer, 0, 1, vertex_buffers, vertex_offset); + vkCmdBindIndexBuffer(g_CommandBuffer, g_IndexBuffer[g_FrameIndex], 0, VK_INDEX_TYPE_UINT16); } + // Setup viewport: { VkViewport viewport; @@ -387,6 +359,7 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) viewport.maxDepth = 1.0f; vkCmdSetViewport(g_CommandBuffer, 0, 1, &viewport); } + // Setup scale and translation: { float scale[2]; @@ -395,39 +368,32 @@ void ImGui_ImplGlfwVulkan_RenderDrawLists(ImDrawData* draw_data) float translate[2]; translate[0] = -1.0f; translate[1] = -1.0f; - vkCmdPushConstants(g_CommandBuffer, - g_PipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, - sizeof(float) * 0, - sizeof(float) * 2, - scale); - vkCmdPushConstants(g_CommandBuffer, - g_PipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, - sizeof(float) * 2, - sizeof(float) * 2, - translate); + vkCmdPushConstants(g_CommandBuffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); + vkCmdPushConstants(g_CommandBuffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); } + // Render the command lists: int vtx_offset = 0; int idx_offset = 0; - for(int n = 0; n < draw_data->CmdListsCount; n++){ + 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++){ + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) + { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if(pcmd->UserCallback){ + if (pcmd->UserCallback) + { pcmd->UserCallback(cmd_list, pcmd); } - else{ + else + { VkRect2D scissor; scissor.offset.x = static_cast(pcmd->ClipRect.x); scissor.offset.y = static_cast(pcmd->ClipRect.y); scissor.extent.width = static_cast(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = static_cast(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // TODO: + 1?????? vkCmdSetScissor(g_CommandBuffer, 0, 1, &scissor); - vkCmdDrawIndexed(g_CommandBuffer, - pcmd->ElemCount, 1, - idx_offset, vtx_offset, 0); + vkCmdDrawIndexed(g_CommandBuffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); } idx_offset += pcmd->ElemCount; } @@ -468,6 +434,7 @@ void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow*, int key, int, int action, int 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]; + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; } void ImGui_ImplGlfwVulkan_CharCallback(GLFWwindow*, unsigned int c) @@ -487,6 +454,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) size_t upload_size = width*height*4*sizeof(char); VkResult err; + // Create the Image: { VkImageCreateInfo info = {}; @@ -500,32 +468,23 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) info.arrayLayers = 1; info.samples = VK_SAMPLE_COUNT_1_BIT; info.tiling = VK_IMAGE_TILING_OPTIMAL; - info.usage = - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - err = vkCreateImage(g_Device, - &info, - g_Allocator, - &g_FontImage); + err = vkCreateImage(g_Device, &info, g_Allocator, &g_FontImage); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetImageMemoryRequirements(g_Device, g_FontImage, &req); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_FontMemory); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_FontMemory); ImGui_ImplGlfwVulkan_VkResult(err); err = vkBindImageMemory(g_Device, g_FontImage, g_FontMemory, 0); ImGui_ImplGlfwVulkan_VkResult(err); } + // Create the Image View: { VkResult err; @@ -537,12 +496,10 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; info.subresourceRange.levelCount = 1; info.subresourceRange.layerCount = 1; - err = vkCreateImageView(g_Device, - &info, - g_Allocator, - &g_FontView); + err = vkCreateImageView(g_Device, &info, g_Allocator, &g_FontView); ImGui_ImplGlfwVulkan_VkResult(err); } + // Update the Descriptor Set: { VkDescriptorImageInfo desc_image[1] = {}; @@ -555,10 +512,9 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) write_desc[0].descriptorCount = 1; write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write_desc[0].pImageInfo = desc_image; - vkUpdateDescriptorSets(g_Device, - 1, write_desc, - 0, NULL); + vkUpdateDescriptorSets(g_Device, 1, write_desc, 0, NULL); } + // Create the Upload Buffer: { VkBufferCreateInfo buffer_info = {}; @@ -566,10 +522,7 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) buffer_info.size = upload_size; buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(g_Device, - &buffer_info, - g_Allocator, - &g_UploadBuffer); + err = vkCreateBuffer(g_Device, &buffer_info, g_Allocator, &g_UploadBuffer); ImGui_ImplGlfwVulkan_VkResult(err); VkMemoryRequirements req; vkGetBufferMemoryRequirements(g_Device, g_UploadBuffer, &req); @@ -577,22 +530,17 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; - alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - req.memoryTypeBits); - err = vkAllocateMemory(g_Device, - &alloc_info, - g_Allocator, - &g_UploadBufferMemory); + alloc_info.memoryTypeIndex = ImGui_ImplGlfwVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(g_Device, &alloc_info, g_Allocator, &g_UploadBufferMemory); ImGui_ImplGlfwVulkan_VkResult(err); err = vkBindBufferMemory(g_Device, g_UploadBuffer, g_UploadBufferMemory, 0); ImGui_ImplGlfwVulkan_VkResult(err); } + // Upload to Buffer: { - char *map; - err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, - reinterpret_cast(&map)); + char* map = NULL; + err = vkMapMemory(g_Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map)); ImGui_ImplGlfwVulkan_VkResult(err); memcpy(map, pixels, upload_size); VkMappedMemoryRange range[1] = {}; @@ -616,21 +564,15 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, - VK_PIPELINE_STAGE_HOST_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, NULL, 0, NULL, 1, copy_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, copy_barrier); + VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; - vkCmdCopyBufferToImage(command_buffer, - g_UploadBuffer, - g_FontImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ®ion); + vkCmdCopyBufferToImage(command_buffer, g_UploadBuffer, g_FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + VkImageMemoryBarrier use_barrier[1] = {}; use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -643,16 +585,11 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(command_buffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, NULL, 0, NULL, 1, use_barrier); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier); } - io.Fonts->TexID = (void *)(intptr_t)g_FontImage; - io.Fonts->ClearInputData(); - io.Fonts->ClearTexData(); + // Store our identifier + io.Fonts->TexID = (void *)(intptr_t)g_FontImage; return true; } @@ -660,7 +597,6 @@ bool ImGui_ImplGlfwVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() { VkResult err; - VkShaderModule vert_module; VkShaderModule frag_module; @@ -679,7 +615,9 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() err = vkCreateShaderModule(g_Device, &frag_info, g_Allocator, &frag_module); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_FontSampler){ + + if (!g_FontSampler) + { VkSamplerCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; info.magFilter = VK_FILTER_LINEAR; @@ -690,13 +628,12 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.minLod = -1000; info.maxLod = 1000; - err = vkCreateSampler(g_Device, - &info, - g_Allocator, - &g_FontSampler); + err = vkCreateSampler(g_Device, &info, g_Allocator, &g_FontSampler); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_DescriptorSetLayout){ + + if (!g_DescriptorSetLayout) + { VkSampler sampler[1] = {g_FontSampler}; VkDescriptorSetLayoutBinding binding[1] = {}; binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; @@ -707,12 +644,10 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; info.bindingCount = 1; info.pBindings = binding; - err = vkCreateDescriptorSetLayout(g_Device, - &info, - g_Allocator, - &g_DescriptorSetLayout); + err = vkCreateDescriptorSetLayout(g_Device, &info, g_Allocator, &g_DescriptorSetLayout); ImGui_ImplGlfwVulkan_VkResult(err); } + // Create Descriptor Set: { VkDescriptorSetAllocateInfo alloc_info = {}; @@ -723,7 +658,9 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() err = vkAllocateDescriptorSets(g_Device, &alloc_info, &g_DescriptorSet); ImGui_ImplGlfwVulkan_VkResult(err); } - if(!g_PipelineLayout){ + + if (!g_PipelineLayout) + { VkPushConstantRange push_constants[2] = {}; push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].offset = sizeof(float) * 0; @@ -738,8 +675,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() layout_info.pSetLayouts = set_layout; layout_info.pushConstantRangeCount = 2; layout_info.pPushConstantRanges = push_constants; - err = vkCreatePipelineLayout(g_Device, &layout_info, - g_Allocator, &g_PipelineLayout); + err = vkCreatePipelineLayout(g_Device, &layout_info, g_Allocator, &g_PipelineLayout); ImGui_ImplGlfwVulkan_VkResult(err); } @@ -805,17 +741,14 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; - color_attachment[0].colorWriteMask = - VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineColorBlendStateCreateInfo blend_info = {}; blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; blend_info.attachmentCount = 1; blend_info.pAttachments = color_attachment; - VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR}; + VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.dynamicStateCount = 2; dynamic_state.pDynamicStates = dynamic_states; @@ -834,11 +767,7 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() info.pDynamicState = &dynamic_state; info.layout = g_PipelineLayout; info.renderPass = g_RenderPass; - err = vkCreateGraphicsPipelines(g_Device, - g_PipelineCache, - 1, &info, - g_Allocator, - &g_Pipeline); + err = vkCreateGraphicsPipelines(g_Device, g_PipelineCache, 1, &info, g_Allocator, &g_Pipeline); ImGui_ImplGlfwVulkan_VkResult(err); vkDestroyShaderModule(g_Device, vert_module, g_Allocator); @@ -849,43 +778,47 @@ bool ImGui_ImplGlfwVulkan_CreateDeviceObjects() void ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects() { - if(g_UploadBuffer){ + if (g_UploadBuffer) + { vkDestroyBuffer(g_Device, g_UploadBuffer, g_Allocator); g_UploadBuffer = VK_NULL_HANDLE; } - if(g_UploadBufferMemory){ + if (g_UploadBufferMemory) + { vkFreeMemory(g_Device, g_UploadBufferMemory, g_Allocator); g_UploadBufferMemory = VK_NULL_HANDLE; } } + void ImGui_ImplGlfwVulkan_InvalidateDeviceObjects() { ImGui_ImplGlfwVulkan_InvalidateFontUploadObjects(); - for(int i=0; i -#include -#include +#include // printf, fprintf +#include // abort #define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_VULKAN #include @@ -47,9 +47,10 @@ static VkClearValue g_ClearValue = {}; static void check_vk_result(VkResult err) { - if(err == 0) return; + if (err == 0) return; printf("VkResult %d\n", err); - if(err < 0) abort(); + if (err < 0) + abort(); } static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) @@ -58,15 +59,17 @@ static void resize_vulkan(GLFWwindow* /*window*/, int w, int h) VkSwapchainKHR old_swapchain = g_Swapchain; err = vkDeviceWaitIdle(g_Device); check_vk_result(err); + // Destroy old Framebuffer: - for(uint32_t i=0; i Date: Sun, 3 Apr 2016 17:41:59 +0200 Subject: [PATCH 12/24] Examples: Libs: Update glfw binaries to glfw master. --- examples/libs/glfw/include/GLFW/glfw3.h | 2034 ++++++++++++----- examples/libs/glfw/include/GLFW/glfw3native.h | 242 +- examples/libs/glfw/lib-vc2010-32/glfw3.lib | Bin 129546 -> 187376 bytes examples/libs/glfw/lib-vc2010-64/glfw3.lib | Bin 202450 -> 291120 bytes 4 files changed, 1624 insertions(+), 652 deletions(-) diff --git a/examples/libs/glfw/include/GLFW/glfw3.h b/examples/libs/glfw/include/GLFW/glfw3.h index 89414491e..f8ca3d61a 100644 --- a/examples/libs/glfw/include/GLFW/glfw3.h +++ b/examples/libs/glfw/include/GLFW/glfw3.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.1 - www.glfw.org + * GLFW 3.2 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -38,58 +38,60 @@ extern "C" { * Doxygen documentation *************************************************************************/ -/*! @defgroup context Context handling +/*! @file glfw3.h + * @brief The header of the GLFW 3 API. * - * This is the reference documentation for context related functions. For more - * information, see the @ref context. + * This is the header file of the GLFW 3 API. It defines all its types and + * declares all its functions. + * + * For more information about how to use this file, see @ref build_include. */ -/*! @defgroup init Initialization, version and errors +/*! @defgroup context Context reference + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. + */ +/*! @defgroup vulkan Vulkan reference + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. + */ +/*! @defgroup init Initialization, version and error reference * * This is the reference documentation for initialization and termination of - * the library, version management and error handling. For more information, - * see the @ref intro. + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. */ -/*! @defgroup input Input handling +/*! @defgroup input Input reference * * This is the reference documentation for input related functions and types. - * For more information, see the @ref input. + * For more task-oriented information, see the @ref input_guide. */ -/*! @defgroup monitor Monitor handling +/*! @defgroup monitor Monitor reference * * This is the reference documentation for monitor related functions and types. - * For more information, see the @ref monitor. + * For more task-oriented information, see the @ref monitor_guide. */ -/*! @defgroup window Window handling +/*! @defgroup window Window reference * * This is the reference documentation for window related functions and types, - * including creation, deletion and event polling. For more information, see - * the @ref window. + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. */ /************************************************************************* - * Global definitions + * Compiler- and platform-specific preprocessor work *************************************************************************/ -/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ - -/* Please report any problems that you find with your compiler, which may - * be solved in this section! There are several compilers that I have not - * been able to test this file with yet. - * - * First: If we are we on Windows, we want a single define for it (_WIN32) - * (Note: For Cygwin the compiler flag -mwin32 should be used, but to - * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ - * to the list of "valid Win32 identifiers", which removes the need for - * -mwin32) +/* If we are we on Windows, we want a single define for it. */ -#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) #define _WIN32 #endif /* _WIN32 */ -/* In order for extension support to be portable, we need to define an - * OpenGL function call method. We use the keyword APIENTRY, which is - * defined for Win32. (Note: Windows also needs this for ) +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ #ifndef APIENTRY #ifdef _WIN32 @@ -99,51 +101,30 @@ extern "C" { #endif #endif /* APIENTRY */ -/* The following three defines are here solely to make some Windows-based - * files happy. Theoretically we could include , but - * it has the major drawback of severely polluting our namespace. +/* Some Windows OpenGL headers need this. */ - -/* Under Windows, we need WINGDIAPI defined */ #if !defined(WINGDIAPI) && defined(_WIN32) - #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) - /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ - #define WINGDIAPI __declspec(dllimport) - #elif defined(__LCC__) - /* LCC-Win32 */ - #define WINGDIAPI __stdcall - #else - /* Others (e.g. MinGW, Cygwin) */ - #define WINGDIAPI extern - #endif + #define WINGDIAPI __declspec(dllimport) #define GLFW_WINGDIAPI_DEFINED #endif /* WINGDIAPI */ -/* Some files also need CALLBACK defined */ +/* Some Windows GLU headers need this. + */ #if !defined(CALLBACK) && defined(_WIN32) - #if defined(_MSC_VER) - /* Microsoft Visual C++ */ - #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) - #define CALLBACK __stdcall - #else - #define CALLBACK - #endif - #else - /* Other Windows compilers */ - #define CALLBACK __stdcall - #endif + #define CALLBACK __stdcall #define GLFW_CALLBACK_DEFINED #endif /* CALLBACK */ -/* Most GL/glu.h variants on Windows need wchar_t - * OpenGL/gl.h blocks the definition of ptrdiff_t by glext.h on OS X */ -#if !defined(GLFW_INCLUDE_NONE) - #include -#endif +/* Most Windows GLU headers need wchar_t. + * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include +#include /* Include the chosen client API headers. */ -#if defined(__APPLE_CC__) +#if defined(__APPLE__) #if defined(GLFW_INCLUDE_GLCOREARB) #include #if defined(GLFW_INCLUDE_GLEXT) @@ -174,13 +155,15 @@ extern "C" { #elif defined(GLFW_INCLUDE_ES3) #include #if defined(GLFW_INCLUDE_GLEXT) - #include + #include #endif #elif defined(GLFW_INCLUDE_ES31) #include #if defined(GLFW_INCLUDE_GLEXT) - #include + #include #endif + #elif defined(GLFW_INCLUDE_VULKAN) + #include #elif !defined(GLFW_INCLUDE_NONE) #include #if defined(GLFW_INCLUDE_GLEXT) @@ -208,11 +191,7 @@ extern "C" { #define GLFWAPI __declspec(dllexport) #elif defined(_WIN32) && defined(GLFW_DLL) /* We are calling GLFW as a Win32 DLL */ - #if defined(__LCC__) - #define GLFWAPI extern - #else - #define GLFWAPI __declspec(dllimport) - #endif + #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) @@ -221,8 +200,6 @@ extern "C" { #define GLFWAPI #endif -/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ - /************************************************************************* * GLFW API tokens @@ -242,7 +219,7 @@ extern "C" { * backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 1 +#define GLFW_VERSION_MINOR 2 /*! @brief The revision number of the GLFW library. * * This is incremented when a bug fix release is made that does not contain any @@ -252,6 +229,24 @@ extern "C" { #define GLFW_VERSION_REVISION 0 /*! @} */ +/*! @name Boolean values + * @{ */ +/*! @brief One. + * + * One. Seriously. You don't _need_ to use this symbol in your code. It's + * just semantic sugar for the number 1. You can use `1` or `true` or `_True` + * or `GL_TRUE` or whatever you want. + */ +#define GLFW_TRUE 1 +/*! @brief Zero. + * + * Zero. Seriously. You don't _need_ to use this symbol in your code. It's + * just just semantic sugar for the number 0. You can use `0` or `false` or + * `_False` or `GL_FALSE` or whatever you want. + */ +#define GLFW_FALSE 0 +/*! @} */ + /*! @name Key and button actions * @{ */ /*! @brief The key or mouse button was released. @@ -426,6 +421,7 @@ extern "C" { #define GLFW_KEY_RIGHT_ALT 346 #define GLFW_KEY_RIGHT_SUPER 347 #define GLFW_KEY_MENU 348 + #define GLFW_KEY_LAST GLFW_KEY_MENU /*! @} */ @@ -505,12 +501,11 @@ extern "C" { * @{ */ /*! @brief GLFW has not been initialized. * - * This occurs if a GLFW function was called that may not be called unless the + * This occurs if a GLFW function was called that must not be called unless the * library is [initialized](@ref intro_init). * - * @par Analysis - * Application programmer error. Initialize GLFW before calling any function - * that requires initialization. + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. */ #define GLFW_NOT_INITIALIZED 0x00010001 /*! @brief No context is current for this thread. @@ -519,9 +514,8 @@ extern "C" { * current OpenGL or OpenGL ES context but no context is current on the calling * thread. One such function is @ref glfwSwapInterval. * - * @par Analysis - * Application programmer error. Ensure a context is current before calling - * functions that require a current context. + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. */ #define GLFW_NO_CURRENT_CONTEXT 0x00010002 /*! @brief One of the arguments to the function was an invalid enum value. @@ -530,8 +524,7 @@ extern "C" { * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref * glfwGetWindowAttrib. * - * @par Analysis - * Application programmer error. Fix the offending call. + * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_ENUM 0x00010003 /*! @brief One of the arguments to the function was an invalid value. @@ -542,46 +535,41 @@ extern "C" { * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead * result in a @ref GLFW_VERSION_UNAVAILABLE error. * - * @par Analysis - * Application programmer error. Fix the offending call. + * @analysis Application programmer error. Fix the offending call. */ #define GLFW_INVALID_VALUE 0x00010004 /*! @brief A memory allocation failed. * * A memory allocation failed. * - * @par Analysis - * A bug in GLFW or the underlying operating system. Report the bug to our - * [issue tracker](https://github.com/glfw/glfw/issues). + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_OUT_OF_MEMORY 0x00010005 -/*! @brief GLFW could not find support for the requested client API on the - * system. +/*! @brief GLFW could not find support for the requested API on the system. * - * GLFW could not find support for the requested client API on the system. + * GLFW could not find support for the requested API on the system. * - * @par Analysis - * The installed graphics driver does not support the requested client API, or - * does not support it via the chosen context creation backend. Below are - * a few examples. + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. * * @par * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only - * supports OpenGL ES via EGL, while Nvidia and Intel only supports it via + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary - * driver. + * driver. Older graphics drivers do not support Vulkan. */ #define GLFW_API_UNAVAILABLE 0x00010006 /*! @brief The requested OpenGL or OpenGL ES version is not available. * - * The requested OpenGL or OpenGL ES version (including any requested profile - * or context option) is not available on this machine. + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. * - * @par Analysis - * The machine does not support your requirements. If your application is - * sufficiently flexible, downgrade your requirements and try again. - * Otherwise, inform the user that their machine does not match your + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your * requirements. * * @par @@ -597,9 +585,9 @@ extern "C" { * A platform-specific error occurred that does not match any of the more * specific categories. * - * @par Analysis - * A bug in GLFW or the underlying operating system. Report the bug to our - * [issue tracker](https://github.com/glfw/glfw/issues). + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_PLATFORM_ERROR 0x00010008 /*! @brief The requested format is not supported or available. @@ -610,8 +598,7 @@ extern "C" { * If emitted when querying the clipboard, the contents of the clipboard could * not be converted to the requested format. * - * @par Analysis - * If emitted during window creation, one or more + * @analysis If emitted during window creation, one or more * [hard constraints](@ref window_hints_hard) did not match any of the * available pixel formats. If your application is sufficiently flexible, * downgrade your requirements and try again. Otherwise, inform the user that @@ -622,6 +609,14 @@ extern "C" { * the user, as appropriate. */ #define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @brief The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_NO_WINDOW_CONTEXT 0x0001000A /*! @} */ #define GLFW_FOCUSED 0x00020001 @@ -631,6 +626,7 @@ extern "C" { #define GLFW_DECORATED 0x00020005 #define GLFW_AUTO_ICONIFY 0x00020006 #define GLFW_FLOATING 0x00020007 +#define GLFW_MAXIMIZED 0x00020008 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -658,7 +654,9 @@ extern "C" { #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 #define GLFW_OPENGL_PROFILE 0x00022008 #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 +#define GLFW_CONTEXT_NO_ERROR 0x0002200A +#define GLFW_NO_API 0 #define GLFW_OPENGL_API 0x00030001 #define GLFW_OPENGL_ES_API 0x00030002 @@ -736,14 +734,37 @@ extern "C" { * Generic function pointer used for returning client API function pointers * without forcing a cast from a regular pointer. * + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in version 3.0. + * @ingroup context */ typedef void (*GLFWglproc)(void); +/*! @brief Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa glfwGetInstanceProcAddress + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +typedef void (*GLFWvkproc)(void); + /*! @brief Opaque monitor object. * * Opaque monitor object. * + * @see @ref monitor_object + * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef struct GLFWmonitor GLFWmonitor; @@ -752,6 +773,10 @@ typedef struct GLFWmonitor GLFWmonitor; * * Opaque window object. * + * @see @ref window_object + * + * @since Added in version 3.0. + * * @ingroup window */ typedef struct GLFWwindow GLFWwindow; @@ -760,6 +785,10 @@ typedef struct GLFWwindow GLFWwindow; * * Opaque cursor object. * + * @see @ref cursor_object + * + * @since Added in version 3.1. + * * @ingroup cursor */ typedef struct GLFWcursor GLFWcursor; @@ -771,8 +800,11 @@ typedef struct GLFWcursor GLFWcursor; * @param[in] error An [error code](@ref errors). * @param[in] description A UTF-8 encoded string describing the error. * + * @sa @ref error_handling * @sa glfwSetErrorCallback * + * @since Added in version 3.0. + * * @ingroup init */ typedef void (* GLFWerrorfun)(int,const char*); @@ -787,8 +819,11 @@ typedef void (* GLFWerrorfun)(int,const char*); * @param[in] ypos The new y-coordinate, in screen coordinates, of the * upper-left corner of the client area of the window. * + * @sa @ref window_pos * @sa glfwSetWindowPosCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); @@ -801,8 +836,12 @@ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); * @param[in] width The new width, in screen coordinates, of the window. * @param[in] height The new height, in screen coordinates, of the window. * + * @sa @ref window_size * @sa glfwSetWindowSizeCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); @@ -813,8 +852,12 @@ typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); * * @param[in] window The window that the user attempted to close. * + * @sa @ref window_close * @sa glfwSetWindowCloseCallback * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowclosefun)(GLFWwindow*); @@ -825,8 +868,12 @@ typedef void (* GLFWwindowclosefun)(GLFWwindow*); * * @param[in] window The window whose content needs to be refreshed. * + * @sa @ref window_refresh * @sa glfwSetWindowRefreshCallback * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * * @ingroup window */ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); @@ -836,11 +883,14 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); * This is the function signature for window focus callback functions. * * @param[in] window The window that gained or lost input focus. - * @param[in] focused `GL_TRUE` if the window was given input focus, or - * `GL_FALSE` if it lost it. + * @param[in] focused `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. * + * @sa @ref window_focus * @sa glfwSetWindowFocusCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); @@ -851,11 +901,14 @@ typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); * functions. * * @param[in] window The window that was iconified or restored. - * @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE` - * if it was restored. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. * + * @sa @ref window_iconify * @sa glfwSetWindowIconifyCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); @@ -869,8 +922,11 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); * @param[in] width The new width, in pixels, of the framebuffer. * @param[in] height The new height, in pixels, of the framebuffer. * + * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * + * @since Added in version 3.0. + * * @ingroup window */ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); @@ -886,8 +942,12 @@ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_mouse_button * @sa glfwSetMouseButtonCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * * @ingroup input */ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); @@ -897,11 +957,16 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); * This is the function signature for cursor position callback functions. * * @param[in] window The window that received the event. - * @param[in] xpos The new x-coordinate, in screen coordinates, of the cursor. - * @param[in] ypos The new y-coordinate, in screen coordinates, of the cursor. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the client area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * client area. * + * @sa @ref cursor_pos * @sa glfwSetCursorPosCallback * + * @since Added in version 3.0. Replaces `GLFWmouseposfun`. + * * @ingroup input */ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); @@ -911,11 +976,14 @@ typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); * This is the function signature for cursor enter/leave callback functions. * * @param[in] window The window that received the event. - * @param[in] entered `GL_TRUE` if the cursor entered the window's client - * area, or `GL_FALSE` if it left it. + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's client + * area, or `GLFW_FALSE` if it left it. * + * @sa @ref cursor_enter * @sa glfwSetCursorEnterCallback * + * @since Added in version 3.0. + * * @ingroup input */ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); @@ -928,8 +996,11 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); * @param[in] xoffset The scroll offset along the x-axis. * @param[in] yoffset The scroll offset along the y-axis. * + * @sa @ref scrolling * @sa glfwSetScrollCallback * + * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. + * * @ingroup input */ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); @@ -945,8 +1016,12 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_key * @sa glfwSetKeyCallback * + * @since Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * * @ingroup input */ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); @@ -958,8 +1033,12 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); * @param[in] window The window that received the event. * @param[in] codepoint The Unicode code point of the character. * + * @sa @ref input_char * @sa glfwSetCharCallback * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter. + * * @ingroup input */ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); @@ -976,8 +1055,11 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * + * @sa @ref input_char * @sa glfwSetCharModsCallback * + * @since Added in version 3.1. + * * @ingroup input */ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); @@ -988,10 +1070,13 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); * * @param[in] window The window that received the event. * @param[in] count The number of dropped files. - * @param[in] names The UTF-8 encoded path names of the dropped files. + * @param[in] paths The UTF-8 encoded file and/or directory path names. * + * @sa @ref path_drop * @sa glfwSetDropCallback * + * @since Added in version 3.1. + * * @ingroup input */ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); @@ -1003,16 +1088,42 @@ typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); * @param[in] monitor The monitor that was connected or disconnected. * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. * + * @sa @ref monitor_event * @sa glfwSetMonitorCallback * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); +/*! @brief The function signature for joystick configuration callbacks. + * + * This is the function signature for joystick configuration callback + * functions. + * + * @param[in] joy The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa @ref joystick_event + * @sa glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int,int); + /*! @brief Video mode type. * * This describes a single video mode. * + * @sa @ref monitor_modes + * @sa glfwGetVideoMode glfwGetVideoModes + * + * @since Added in version 1.0. + * @glfw3 Added refresh rate member. + * * @ingroup monitor */ typedef struct GLFWvidmode @@ -1041,8 +1152,11 @@ typedef struct GLFWvidmode * * This describes the gamma ramp for a monitor. * + * @sa @ref monitor_gamma * @sa glfwGetGammaRamp glfwSetGammaRamp * + * @since Added in version 3.0. + * * @ingroup monitor */ typedef struct GLFWgammaramp @@ -1062,6 +1176,11 @@ typedef struct GLFWgammaramp } GLFWgammaramp; /*! @brief Image data. + * + * @sa @ref cursor_custom + * + * @since Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. */ typedef struct GLFWimage { @@ -1092,29 +1211,24 @@ typedef struct GLFWimage * succeeds, you should call @ref glfwTerminate before the application exits. * * Additional calls to this function after successful initialization but before - * termination will return `GL_TRUE` immediately. + * termination will return `GLFW_TRUE` immediately. * - * @return `GL_TRUE` if successful, or `GL_FALSE` if an + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an * [error](@ref error_handling) occurred. * - * @remarks __OS X:__ This function will change the current directory of the + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark @osx This function will change the current directory of the * application to the `Contents/Resources` subdirectory of the application's * bundle, if present. This can be disabled with a * [compile-time option](@ref compile_options_osx). * - * @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to - * `"C"` then the environment's locale will be applied to that category. This - * is done because character input will not function when `LC_CTYPE` is set to - * `"C"`. If another locale was set before this function was called, it will - * be left untouched. - * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init * @sa glfwTerminate * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup init */ @@ -1132,21 +1246,21 @@ GLFWAPI int glfwInit(void); * call this function, as it is called by @ref glfwInit before it returns * failure. * - * @remarks This function may be called before @ref glfwInit. + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. * - * @warning No window's context may be current on another thread when this - * function is called. + * @remark This function may be called before @ref glfwInit. * - * @par Reentrancy - * This function may not be called from a callback. + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref intro_init * @sa glfwInit * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup init */ @@ -1158,22 +1272,22 @@ GLFWAPI void glfwTerminate(void); * library. It is intended for when you are using GLFW as a shared library and * want to ensure that you are using the minimum required version. * - * Any or all of the version arguments may be `NULL`. This function always - * succeeds. + * Any or all of the version arguments may be `NULL`. * * @param[out] major Where to store the major version number, or `NULL`. * @param[out] minor Where to store the minor version number, or `NULL`. * @param[out] rev Where to store the revision number, or `NULL`. * - * @remarks This function may be called before @ref glfwInit. + * @errors None. * - * @par Thread Safety - * This function may be called from any thread. + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. * * @sa @ref intro_version * @sa glfwGetVersionString * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup init */ @@ -1184,28 +1298,27 @@ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); * This function returns the compile-time generated * [version string](@ref intro_version_string) of the GLFW library binary. It * describes the version, platform, compiler and any platform-specific - * compile-time options. + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. * * __Do not use the version string__ to parse the GLFW library version. The - * @ref glfwGetVersion function already provides the version of the running - * library binary. + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. * - * This function always succeeds. + * @return The ASCII encoded GLFW version string. * - * @return The GLFW version string. + * @errors None. * - * @remarks This function may be called before @ref glfwInit. + * @remark This function may be called before @ref glfwInit. * - * @par Pointer Lifetime - * The returned string is static and compile-time generated. + * @pointer_lifetime The returned string is static and compile-time generated. * - * @par Thread Safety - * This function may be called from any thread. + * @thread_safety This function may be called from any thread. * * @sa @ref intro_version * @sa glfwGetVersion * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup init */ @@ -1231,14 +1344,15 @@ GLFWAPI const char* glfwGetVersionString(void); * callback. * @return The previously set callback, or `NULL` if no callback was set. * - * @remarks This function may be called before @ref glfwInit. + * @errors None. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref error_handling * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup init */ @@ -1247,26 +1361,27 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); /*! @brief Returns the currently connected monitors. * * This function returns an array of handles for all currently connected - * monitors. + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `NULL`. * * @param[out] count Where to store the number of monitors in the returned * array. This is set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if an - * [error](@ref error_handling) occurred. + * @return An array of monitor handles, or `NULL` if no monitors were found or + * if an [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is guaranteed to be valid only until the monitor configuration - * changes or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_monitors * @sa @ref monitor_event * @sa glfwGetPrimaryMonitor * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1275,18 +1390,22 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); /*! @brief Returns the primary monitor. * * This function returns the primary monitor. This is usually the monitor - * where elements like the Windows task bar or the OS X menu bar is located. + * where elements like the task bar or global menu bar are located. * - * @return The primary monitor, or `NULL` if an [error](@ref error_handling) - * occurred. + * @return The primary monitor, or `NULL` if no monitors were found or if an + * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. * * @sa @ref monitor_monitors * @sa glfwGetMonitors * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1304,12 +1423,14 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1334,15 +1455,16 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * @param[out] heightMM Where to store the height, in millimetres, of the * monitor's display area, or `NULL`. * - * @remarks __Windows:__ The OS calculates the returned physical size from the + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 calculates the returned physical size from the * current resolution and system DPI instead of querying the monitor EDID data. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1358,17 +1480,17 @@ GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* * @return The UTF-8 encoded name of the monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified monitor is disconnected or the - * library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_properties * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1385,15 +1507,13 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @bug __X11:__ This callback is not yet called on monitor configuration - * changes. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_event * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1412,21 +1532,21 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); * @return An array of video modes, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified monitor is disconnected, this - * function is called again for that monitor or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_modes * @sa glfwGetVideoMode * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Changed to return an array of modes for a specific monitor. + * @since Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. * * @ingroup monitor */ @@ -1442,18 +1562,19 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); * @return The current mode of the monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified monitor is disconnected or the - * library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_modes * @sa glfwGetVideoModes * - * @since Added in GLFW 3.0. Replaces `glfwGetDesktopMode`. + * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. * * @ingroup monitor */ @@ -1462,17 +1583,20 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); /*! @brief Generates a gamma ramp and sets it for the specified monitor. * * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. + * and then calls @ref glfwSetGammaRamp with it. The value must be a finite + * number greater than zero. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1486,18 +1610,19 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); * @return The current gamma ramp, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned structure and its arrays are allocated and freed by GLFW. You - * should not free them yourself. They are valid until the specified monitor - * is disconnected, this function is called again for that monitor or the - * library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1512,17 +1637,22 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * - * @note Gamma ramp sizes other than 256 are not supported by all hardware. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Pointer Lifetime - * The specified gamma ramp is copied before this function returns. + * @remark Gamma ramp sizes other than 256 are not supported by all platforms + * or graphics hardware. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark @win32 The gamma ramp size must be 256. + * + * @pointer_lifetime The specified gamma ramp is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref monitor_gamma * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup monitor */ @@ -1533,13 +1663,14 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); * This function resets all window hints to their * [default values](@ref window_hints_values). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa glfwWindowHint * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1552,20 +1683,26 @@ GLFWAPI void glfwDefaultWindowHints(void); * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is * terminated. * - * @param[in] target The [window hint](@ref window_hints) to set. - * @param[in] hint The new value of the window hint. + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. * - * @par Thread Safety - * This function may only be called from the main thread. + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints * @sa glfwDefaultWindowHints * - * @since Added in GLFW 3.0. Replaces `glfwOpenWindowHint`. + * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. * * @ingroup window */ -GLFWAPI void glfwWindowHint(int target, int hint); +GLFWAPI void glfwWindowHint(int hint, int value); /*! @brief Creates a window and its associated context. * @@ -1582,21 +1719,21 @@ GLFWAPI void glfwWindowHint(int target, int hint); * requested, as not all parameters and hints are * [hard constraints](@ref window_hints_hard). This includes the size of the * window, especially for full screen windows. To query the actual attributes - * of the created window, framebuffer and context, use queries like @ref - * glfwGetWindowAttrib and @ref glfwGetWindowSize. + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. * * To create a full screen window, you need to specify the monitor the window - * will cover. If no monitor is specified, windowed mode will be used. Unless - * you have a way for the user to choose a specific monitor, it is recommended - * that you pick the primary monitor. For more information on how to query - * connected monitors, see @ref monitor_monitors. + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. * * For full screen windows, the specified size becomes the resolution of the - * window's _desired video mode_. As long as a full screen window has input - * focus, the supported video mode most closely matching the desired video mode - * is set for the specified monitor. For more information about full screen - * windows, including the creation of so called _windowed full screen_ or - * _borderless full screen_ windows, see @ref window_windowed_full_screen. + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. * * By default, newly created windows use the placement recommended by the * window system. To create the window at a specific position, make it @@ -1604,8 +1741,8 @@ GLFWAPI void glfwWindowHint(int target, int hint); * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) * it. * - * If a full screen window has input focus, the screensaver is prohibited from - * starting. + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. * * Window systems put limits on window sizes. Very large or very small window * dimensions may be overridden by the window system on creation. Check the @@ -1619,50 +1756,67 @@ GLFWAPI void glfwWindowHint(int target, int hint); * @param[in] height The desired height, in screen coordinates, of the window. * This must be greater than zero. * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` to use + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. * @return The handle of the created window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @remarks __Windows:__ Window creation will fail if the Microsoft GDI - * software OpenGL implementation is the only one available. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. * - * @remarks __Windows:__ If the executable has an icon resource named - * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is - * present, the `IDI_WINLOGO` icon will be used instead. + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. * - * @remarks __Windows:__ The context to share resources with may not be current - * on any other thread. + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` + * it will be set as the icon for the window. If no such icon is present, the + * `IDI_WINLOGO` icon will be used instead. * - * @remarks __OS X:__ The GLFW window has no icon, as it is not a document + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @osx The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. * For more information on bundles, see the * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) * in the Mac Developer Library. * - * @remarks __OS X:__ The first time a window is created the menu bar is - * populated with common commands like Hide, Quit and About. The About entry - * opens a minimal about dialog with information from the application's bundle. - * The menu bar can be disabled with a + * @remark @osx The first time a window is created the menu bar is populated + * with common commands like Hide, Quit and About. The About entry opens + * a minimal about dialog with information from the application's bundle. The + * menu bar can be disabled with a * [compile-time option](@ref compile_options_osx). * - * @remarks __X11:__ There is no mechanism for setting the window icon yet. + * @remark @osx On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the `NSHighResolutionCapable` + * key is enabled in the application bundle's `Info.plist`. For more + * information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. * - * @remarks __X11:__ Some window managers will not respect the placement of + * @remark @x11 There is no mechanism for setting the window icon yet. + * + * @remark @x11 Some window managers will not respect the placement of * initially hidden windows. * - * @par Reentrancy - * This function may not be called from a callback. + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation * @sa glfwDestroyWindow * - * @since Added in GLFW 3.0. Replaces `glfwOpenWindow`. + * @since Added in version 3.0. Replaces `glfwOpenWindow`. * * @ingroup window */ @@ -1678,19 +1832,20 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G * * @param[in] window The window to destroy. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * * @note The context of the specified window must not be current on any other * thread when this function is called. * - * @par Reentrancy - * This function may not be called from a callback. + * @reentrancy This function must not be called from a callback. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_creation * @sa glfwCreateWindow * - * @since Added in GLFW 3.0. Replaces `glfwCloseWindow`. + * @since Added in version 3.0. Replaces `glfwCloseWindow`. * * @ingroup window */ @@ -1703,12 +1858,14 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); * @param[in] window The window to query. * @return The value of the close flag. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_close * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1723,12 +1880,14 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); * @param[in] window The window whose flag to change. * @param[in] value The new value. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_close * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1742,20 +1901,62 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); * @param[in] window The window whose title to change. * @param[in] title The UTF-8 encoded window title. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @osx The window title will not be updated until the next time you + * process events. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_title * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @osx The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + /*! @brief Retrieves the position of the client area of the specified window. * * This function retrieves the position, in screen coordinates, of the @@ -1770,13 +1971,15 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * @param[out] ypos Where to store the y-coordinate of the upper-left corner of * the client area, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * @sa glfwSetWindowPos * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1798,16 +2001,16 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); * @param[in] xpos The x-coordinate of the upper-left corner of the client area. * @param[in] ypos The y-coordinate of the upper-left corner of the client area. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * @sa glfwGetWindowPos * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1828,48 +2031,131 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * @param[out] height Where to store the height, in screen coordinates, of the * client area, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * @sa glfwSetWindowSize * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); +/*! @brief Sets the size limits of the specified window. + * + * This function sets the size limits of the client area of the specified + * window. If the window is full screen, the size limits only take effect if + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] minwidth The minimum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] minheight The minimum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the client + * area, or `GLFW_DONT_CARE`. + * @param[in] maxheight The maximum height, in screen coordinates, of the + * client area, or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowAspectRatio + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @brief Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the client area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] numer The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * @param[in] denom The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa glfwSetWindowSizeLimits + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + /*! @brief Sets the size of the client area of the specified window. * * This function sets the size, in screen coordinates, of the client area of * the specified window. * - * For full screen windows, this function selects and switches to the resolution - * closest to the specified size, without affecting the window's context. As - * the context is unaffected, the bit depths of the framebuffer remain - * unchanged. + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. * * The window manager may put limits on what sizes are allowed. GLFW cannot * and should not override these limits. * * @param[in] window The window to resize. - * @param[in] width The desired width of the specified window. - * @param[in] height The desired height of the specified window. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * @sa glfwGetWindowSize + * @sa glfwSetWindowMonitor * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1890,13 +2176,15 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); * @param[out] height Where to store the height, in pixels, of the framebuffer, * or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -1926,12 +2214,14 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height) * @param[out] bottom Where to store the size, in screen coordinates, of the * bottom edge of the window frame, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup window */ @@ -1948,16 +2238,17 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int * * @param[in] window The window to iconify. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify * @sa glfwRestoreWindow + * @sa glfwMaximizeWindow * - * @since Added in GLFW 2.1. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -1966,27 +2257,51 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * * This function restores the specified window if it was previously iconified - * (minimized). If the window is already restored, this function does nothing. + * (minimized) or maximized. If the window is already restored, this function + * does nothing. * * If the specified window is a full screen window, the resolution chosen for * the window is restored on the selected monitor. * * @param[in] window The window to restore. * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa glfwIconifyWindow + * @sa glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwRestoreWindow(GLFWwindow* window); + +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * * @par Thread Safety * This function may only be called from the main thread. * * @sa @ref window_iconify * @sa glfwIconifyWindow + * @sa glfwRestoreWindow * - * @since Added in GLFW 2.1. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in GLFW 3.2. * * @ingroup window */ -GLFWAPI void glfwRestoreWindow(GLFWwindow* window); +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); /*! @brief Makes the specified window visible. * @@ -1996,13 +2311,15 @@ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); * * @param[in] window The window to make visible. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide * @sa glfwHideWindow * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2016,18 +2333,48 @@ GLFWAPI void glfwShowWindow(GLFWwindow* window); * * @param[in] window The window to hide. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hide * @sa glfwShowWindow * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ GLFWAPI void glfwHideWindow(GLFWwindow* window); +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref window_hints_wnd) to disable + * this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(GLFWwindow* window); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is @@ -2037,17 +2384,67 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * @return The monitor, or `NULL` if the window is in windowed mode or an error * occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor + * @sa glfwSetWindowMonitor * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc.. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa glfwGetWindowMonitor + * @sa glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns an attribute of the specified window. * * This function returns the value of an attribute of the specified window or @@ -2059,12 +2456,22 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); * @return The value of the attribute, or zero if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_attribs * - * @since Added in GLFW 3.0. Replaces `glfwGetWindowParam` and + * @since Added in version 3.0. Replaces `glfwGetWindowParam` and * `glfwGetGLVersion`. * * @ingroup window @@ -2080,13 +2487,15 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * @param[in] window The window whose pointer to set. * @param[in] pointer The new value. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_userptr * @sa glfwGetWindowUserPointer * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2099,13 +2508,15 @@ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); * * @param[in] window The window whose pointer to return. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * * @sa @ref window_userptr * @sa glfwSetWindowUserPointer * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2123,12 +2534,13 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_pos * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2146,15 +2558,14 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindow * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_size * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -2177,18 +2588,17 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @remarks __OS X:__ Selecting Quit from the application menu will - * trigger the close callback for all windows. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark @osx Selecting Quit from the application menu will trigger the close + * callback for all windows. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_close * - * @since Added in GLFW 2.5. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -2210,15 +2620,14 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_refresh * - * @since Added in GLFW 2.5. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. * * @ingroup window */ @@ -2240,12 +2649,13 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_focus * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2262,12 +2672,13 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_iconify * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2284,12 +2695,13 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref window_fbsize * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup window */ @@ -2313,16 +2725,18 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window * * Event processing is not required for joystick input to work. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa glfwWaitEvents + * @sa glfwWaitEventsTimeout * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup window */ @@ -2356,21 +2770,69 @@ GLFWAPI void glfwPollEvents(void); * * Event processing is not required for joystick input to work. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref events * @sa glfwPollEvents + * @sa glfwWaitEventsTimeout * - * @since Added in GLFW 2.5. + * @since Added in version 2.5. * * @ingroup window */ GLFWAPI void glfwWaitEvents(void); +/*! @brief Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * Event processing is not required for joystick input to work. + * + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa glfwPollEvents + * @sa glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + /*! @brief Posts an empty event to the event queue. * * This function posts an empty event from the current thread to the event @@ -2380,13 +2842,15 @@ GLFWAPI void glfwWaitEvents(void); * of threads in applications that do not create windows, use your threading * library of choice. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * * @sa @ref events * @sa glfwWaitEvents * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup window */ @@ -2402,12 +2866,14 @@ GLFWAPI void glfwPostEmptyEvent(void); * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa glfwSetInputMode * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -2428,37 +2894,96 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * and unlimited cursor movement. This is useful for implementing for * example 3D camera controls. * - * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to - * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` * the next time it is called even if the key had been released before the * call. This is useful when you are only interested in whether keys have been * pressed but not when or in which order. * * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either - * `GL_TRUE` to enable sticky mouse buttons, or `GL_FALSE` to disable it. If - * sticky mouse buttons are enabled, a mouse button press will ensure that @ref - * glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even if - * the mouse button had been released before the call. This is useful when you - * are only interested in whether mouse buttons have been pressed but not when - * or in which order. + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. * * @param[in] window The window whose input mode to set. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * @param[in] value The new value of the specified input mode. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa glfwGetInputMode * - * @since Added in GLFW 3.0. Replaces `glfwEnable` and `glfwDisable`. + * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. * * @ingroup input */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); +/*! @brief Returns the localized name of the specified printable key. + * + * This function returns the localized name of the specified printable key. + * This is intended for displaying key bindings to the user. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used instead, otherwise + * the scancode is ignored. If a non-printable key or (if the key is + * `GLFW_KEY_UNKNOWN`) a scancode that maps to a non-printable key is + * specified, this function returns `NULL`. + * + * This behavior allows you to pass in the arguments passed to the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. + * @param[in] scancode The scancode of the key to query. + * @return The localized name of the key, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref + * glfwGetKeyName, or until the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetKeyName(int key, int scancode); + /*! @brief Returns the last reported state of a keyboard key for the specified * window. * @@ -2478,20 +3003,22 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * The [modifier key bit masks](@ref mods) are not key tokens and cannot be * used with this function. * + * __Do not use this function__ to implement [text input](@ref input_char). + * * @param[in] window The desired window. * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is * not a valid key for this function. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup input */ @@ -2512,15 +3039,15 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); * @param[in] button The desired [mouse button](@ref buttons). * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_mouse_button * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup input */ @@ -2550,13 +3077,15 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); * @param[out] ypos Where to store the cursor y-coordinate, relative to the to * top edge of the client area, or `NULL`. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * @sa glfwSetCursorPos * - * @since Added in GLFW 3.0. Replaces `glfwGetMousePos`. + * @since Added in version 3.0. Replaces `glfwGetMousePos`. * * @ingroup input */ @@ -2585,17 +3114,19 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * @param[in] ypos The desired y-coordinate, relative to the top edge of the * client area. * - * @remarks __X11:__ Due to the asynchronous nature of a modern X desktop, it - * may take a moment for the window focus event to arrive. This means you will - * not be able to set the cursor position directly after window creation. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * the window focus event to arrive. This means you may not be able to set the + * cursor position directly after window creation. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * @sa glfwGetCursorPos * - * @since Added in GLFW 3.0. Replaces `glfwSetMousePos`. + * @since Added in version 3.0. Replaces `glfwSetMousePos`. * * @ingroup input */ @@ -2607,9 +3138,9 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. * Any remaining cursors are destroyed by @ref glfwTerminate. * - * The pixels are 32-bit little-endian RGBA, i.e. eight bits per channel. They - * are arranged canonically as packed sequential rows, starting from the - * top-left corner. + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel. They are arranged canonically as packed sequential rows, + * starting from the top-left corner. * * The cursor hotspot is specified in pixels, relative to the upper-left corner * of the cursor image. Like all other coordinate systems in GLFW, the X-axis @@ -2618,24 +3149,24 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @param[in] image The desired cursor image. * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. - * * @return The handle of the created cursor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The specified image data is copied before this function returns. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Reentrancy - * This function may not be called from a callback. + * @pointer_lifetime The specified image data is copied before this function + * returns. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa glfwDestroyCursor * @sa glfwCreateStandardCursor * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2647,20 +3178,20 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) * a window with @ref glfwSetCursor. * * @param[in] shape One of the [standard shapes](@ref shapes). - * * @return A new cursor ready to use or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa glfwCreateCursor * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2674,16 +3205,17 @@ GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); * * @param[in] cursor The cursor object to destroy. * - * @par Reentrancy - * This function may not be called from a callback. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * @sa glfwCreateCursor * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2703,12 +3235,14 @@ GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); * @param[in] cursor The cursor to set, or `NULL` to switch back to the default * arrow cursor. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_object * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2744,15 +3278,14 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_key * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -2783,15 +3316,14 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 2.4. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 2.4. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -2818,12 +3350,13 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * error occurred. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_char * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2846,15 +3379,14 @@ GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmods * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref input_mouse_button * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. * * @ingroup input */ @@ -2873,12 +3405,13 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmo * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_pos * - * @since Added in GLFW 3.0. Replaces `glfwSetMousePosCallback`. + * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. * * @ingroup input */ @@ -2896,12 +3429,13 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursor * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref cursor_enter * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -2922,12 +3456,13 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref scrolling * - * @since Added in GLFW 3.0. Replaces `glfwSetMouseWheelCallback`. + * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. * * @ingroup input */ @@ -2949,12 +3484,13 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb * @return The previously set callback, or `NULL` if no callback was set or the * library had not been [initialized](@ref intro_init). * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref path_drop * - * @since Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup input */ @@ -2965,14 +3501,16 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); * This function returns whether the specified joystick is present. * * @param[in] joy The [joystick](@ref joysticks) to query. - * @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise. + * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick * - * @since Added in GLFW 3.0. Replaces `glfwGetJoystickParam`. + * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. * * @ingroup input */ @@ -2983,22 +3521,28 @@ GLFWAPI int glfwJoystickPresent(int joy); * This function returns the values of all axes of the specified joystick. * Each element in the array is a value between -1.0 and 1.0. * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * * @param[in] joy The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of axis values in the returned * array. This is set to zero if an error occurred. * @return An array of axis values, or `NULL` if the joystick is not present. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified joystick is disconnected, this - * function is called again for that joystick or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_axis * - * @since Added in GLFW 3.0. Replaces `glfwGetJoystickPos`. + * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. * * @ingroup input */ @@ -3009,25 +3553,29 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); * This function returns the state of all buttons of the specified joystick. * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * * @param[in] joy The [joystick](@ref joysticks) to query. * @param[out] count Where to store the number of button states in the returned * array. This is set to zero if an error occurred. * @return An array of button states, or `NULL` if the joystick is not present. * - * @par Pointer Lifetime - * The returned array is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified joystick is disconnected, this - * function is called again for that joystick or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_button * - * @since Added in GLFW 2.2. - * - * @par - * __GLFW 3:__ Changed to return a dynamic array. + * @since Added in version 2.2. + * @glfw3 Changed to return a dynamic array. * * @ingroup input */ @@ -3039,26 +3587,55 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); * The returned string is allocated and freed by GLFW. You should not free it * yourself. * + * Querying a joystick slot with no device present is not an error, but will + * cause this function to return `NULL`. Call @ref glfwJoystickPresent to + * check device presence. + * * @param[in] joy The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick * is not present. * - * @par Pointer Lifetime - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the specified joystick is disconnected, this - * function is called again for that joystick or the library is terminated. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref joystick_name * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ GLFWAPI const char* glfwGetJoystickName(int joy); +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun); + /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded @@ -3067,16 +3644,18 @@ GLFWAPI const char* glfwGetJoystickName(int joy); * @param[in] window The window that will own the clipboard contents. * @param[in] string A UTF-8 encoded string. * - * @par Pointer Lifetime - * The specified string is copied before this function returns. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. * - * @par Thread Safety - * This function may only be called from the main thread. + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa glfwGetClipboardString * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -3085,25 +3664,28 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); /*! @brief Returns the contents of the clipboard as a string. * * This function returns the contents of the system clipboard, if it contains - * or is convertible to a UTF-8 encoded string. + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `NULL` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. * * @param[in] window The window that will request the clipboard contents. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * - * @par Pointer Lifetime - * The returned string is allocated and freed by GLFW. You should not free it - * yourself. It is valid until the next call to @ref + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the next call to @ref * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library * is terminated. * - * @par Thread Safety - * This function may only be called from the main thread. + * @thread_safety This function must only be called from the main thread. * * @sa @ref clipboard * @sa glfwSetClipboardString * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup input */ @@ -3122,12 +3704,14 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * @return The current value, in seconds, or zero if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Reading of the + * internal timer offset is not atomic. * * @sa @ref time * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup input */ @@ -3136,21 +3720,71 @@ GLFWAPI double glfwGetTime(void); /*! @brief Sets the GLFW timer. * * This function sets the value of the GLFW timer. It then continues to count - * up from that value. + * up from that value. The value must be a positive finite number less than + * or equal to 18446744073.0, which is approximately 584.5 years. * * @param[in] time The new value, in seconds. * - * @par Thread Safety - * This function may only be called from the main thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of the timer is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @thread_safety This function may be called from any thread. Writing of the + * internal timer offset is not atomic. * * @sa @ref time * - * @since Added in GLFW 2.2. + * @since Added in version 2.2. * * @ingroup input */ GLFWAPI void glfwSetTime(double time); +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerFrequency(void); + /*! @brief Makes the context of the specified window current for the calling * thread. * @@ -3164,16 +3798,22 @@ GLFWAPI void glfwSetTime(double time); * whether a context performs this flush by setting the * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_current * @sa glfwGetCurrentContext * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup context */ @@ -3187,13 +3827,14 @@ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); * @return The window whose context is current, or `NULL` if no window's * context is current. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_current * @sa glfwMakeContextCurrent * - * @since Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup context */ @@ -3201,22 +3842,33 @@ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); /*! @brief Swaps the front and back buffers of the specified window. * - * This function swaps the front and back buffers of the specified window. If - * the swap interval is greater than zero, the GPU driver waits the specified - * number of screen updates before swapping the buffers. + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. * * @param[in] window The window whose buffers to swap. * - * @par Thread Safety - * This function may be called from any thread. + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. + * + * @thread_safety This function may be called from any thread. * * @sa @ref buffer_swap * @sa glfwSwapInterval * - * @since Added in GLFW 1.0. - * - * @par - * __GLFW 3:__ Added window handle parameter. + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. * * @ingroup window */ @@ -3224,11 +3876,11 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * - * This function sets the swap interval for the current context, i.e. the - * number of screen updates to wait from the time @ref glfwSwapBuffers was - * called before swapping the buffers and returning. This is sometimes called - * _vertical synchronization_, _vertical retrace synchronization_ or just - * _vsync_. + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. * * Contexts that support either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, @@ -3240,25 +3892,30 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * - * @note This function is not called during window creation, leaving the swap - * interval set to whatever is the default on that platform. This is done + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done * because some swap interval extensions used by GLFW do not allow the swap * interval to be reset to zero once it has been set to a non-zero value. * - * @note Some GPU drivers do not honor the requested swap interval, either - * because of user settings that override the request or due to bugs in the - * driver. + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. * - * @par Thread Safety - * This function may be called from any thread. + * @thread_safety This function may be called from any thread. * * @sa @ref buffer_swap * @sa glfwSwapBuffers * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup context */ @@ -3268,8 +3925,8 @@ GLFWAPI void glfwSwapInterval(int interval); * * This function returns whether the specified * [API extension](@ref context_glext) is supported by the current OpenGL or - * OpenGL ES context. It searches both for OpenGL and OpenGL ES extension and - * platform-specific context creation API extensions. + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. @@ -3279,16 +3936,24 @@ GLFWAPI void glfwSwapInterval(int interval); * frequently. The extension strings will not change during the lifetime of * a context, so there is no danger in doing this. * - * @param[in] extension The ASCII encoded name of the extension. - * @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise. + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. * - * @par Thread Safety - * This function may be called from any thread. + * @param[in] extension The ASCII encoded name of the extension. + * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_glext * @sa glfwGetProcAddress * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup context */ @@ -3297,36 +3962,243 @@ GLFWAPI int glfwExtensionSupported(const char* extension); /*! @brief Returns the address of the specified function for the current * context. * - * This function returns the address of the specified - * [client API or extension function](@ref context_glext), if it is supported + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported * by the current context. * * A context must be current on the calling thread. Calling this function * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. * - * @param[in] procname The ASCII encoded name of the function. - * @return The address of the function, or `NULL` if the function is - * unavailable or an [error](@ref error_handling) occurred. + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. * - * @note The addresses of a given function is not guaranteed to be the same + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark The address of a given function is not guaranteed to be the same * between contexts. * - * @par Pointer Lifetime - * The returned function pointer is valid until the context is destroyed or the - * library is terminated. + * @remark This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. * - * @par Thread Safety - * This function may be called from any thread. + * @pointer_lifetime The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * @thread_safety This function may be called from any thread. * * @sa @ref context_glext * @sa glfwExtensionSupported * - * @since Added in GLFW 1.0. + * @since Added in version 1.0. * * @ingroup context */ GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); +/*! @brief Returns whether the Vulkan loader has been found. + * + * This function returns whether the Vulkan loader has been found. This check + * is performed by @ref glfwInit. + * + * The availability of a Vulkan loader does not by itself guarantee that window + * surface creation or even device creation is possible. Call @ref + * glfwGetRequiredInstanceExtensions to check whether the extensions necessary + * for Vulkan surface creation are available and @ref + * glfwGetPhysicalDevicePresentationSupport to check whether a queue family of + * a physical device supports image presentation. + * + * @return `GLFW_TRUE` if Vulkan is available, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwVulkanSupported(void); + +/*! @brief Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contains `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `NULL`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * @param[out] count Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * @return An array of ASCII encoded extension names, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remarks Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa glfwCreateWindowSurface + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); + +#if defined(VK_VERSION_1_0) + +/*! @brief Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `NULL` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve + * functions related to instance creation. + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @pointer_lifetime The returned function pointer is valid until the library + * is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); + +/*! @brief Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * @param[in] instance The instance that the physical device belongs to. + * @param[in] device The physical device that the queue family belongs to. + * @param[in] queuefamily The index of the queue family to query. + * @return `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @brief Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader was not found at initialization, this function returns + * `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref GLFW_API_UNAVAILABLE + * error. Call @ref glfwVulkanSupported to check whether the Vulkan loader was + * found. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * @param[in] instance The Vulkan instance to create the surface in. + * @param[in] window The window to create the surface for. + * @param[in] allocator The allocator to use, or `NULL` to use the default + * allocator. + * @param[out] surface Where to store the handle of the surface. This is set + * to `VK_NULL_HANDLE` if an error occurred. + * @return `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remarks If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa glfwGetRequiredInstanceExtensions + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +#endif /*VK_VERSION_1_0*/ + /************************************************************************* * Global definition cleanup diff --git a/examples/libs/glfw/include/GLFW/glfw3native.h b/examples/libs/glfw/include/GLFW/glfw3native.h index b3ce7482d..9fa955e94 100644 --- a/examples/libs/glfw/include/GLFW/glfw3native.h +++ b/examples/libs/glfw/include/GLFW/glfw3native.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.1 - www.glfw.org + * GLFW 3.2 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -38,20 +38,30 @@ extern "C" { * Doxygen documentation *************************************************************************/ +/*! @file glfw3native.h + * @brief The header of the native access functions. + * + * This is the header file of the native access functions. See @ref native for + * more information. + */ /*! @defgroup native Native access * * **By using the native access functions you assert that you know what you're * doing and how to fix problems caused by using them. If you don't, you * shouldn't be using them.** * - * Before the inclusion of @ref glfw3native.h, you must define exactly one - * window system API macro and exactly one context creation API macro. Failure - * to do this will cause a compile-time error. + * Before the inclusion of @ref glfw3native.h, you may define exactly one + * window system API macro and zero or more context creation API macros. + * + * The chosen backends must match those the library was compiled for. Failure + * to do this will cause a link-time error. * * The available window API macros are: * * `GLFW_EXPOSE_NATIVE_WIN32` * * `GLFW_EXPOSE_NATIVE_COCOA` * * `GLFW_EXPOSE_NATIVE_X11` + * * `GLFW_EXPOSE_NATIVE_WAYLAND` + * * `GLFW_EXPOSE_NATIVE_MIR` * * The available context API macros are: * * `GLFW_EXPOSE_NATIVE_WGL` @@ -86,20 +96,23 @@ extern "C" { #elif defined(GLFW_EXPOSE_NATIVE_X11) #include #include -#else - #error "No window API selected" +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + #include +#elif defined(GLFW_EXPOSE_NATIVE_MIR) + #include #endif #if defined(GLFW_EXPOSE_NATIVE_WGL) /* WGL is declared by windows.h */ -#elif defined(GLFW_EXPOSE_NATIVE_NSGL) +#endif +#if defined(GLFW_EXPOSE_NATIVE_NSGL) /* NSGL is declared by Cocoa.h */ -#elif defined(GLFW_EXPOSE_NATIVE_GLX) +#endif +#if defined(GLFW_EXPOSE_NATIVE_GLX) #include -#elif defined(GLFW_EXPOSE_NATIVE_EGL) +#endif +#if defined(GLFW_EXPOSE_NATIVE_EGL) #include -#else - #error "No context API selected" #endif @@ -114,11 +127,10 @@ extern "C" { * of the specified monitor, or `NULL` if an [error](@ref error_handling) * occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -130,11 +142,10 @@ GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -145,11 +156,10 @@ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); * @return The `HWND` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -162,11 +172,10 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); * @return The `HGLRC` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -179,11 +188,10 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); * @return The `CGDirectDisplayID` of the specified monitor, or * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -194,11 +202,10 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); * @return The `NSWindow` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -211,11 +218,10 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); * @return The `NSOpenGLContext` of the specified window, or `nil` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -228,11 +234,10 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); * @return The `Display` used by GLFW, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -243,11 +248,10 @@ GLFWAPI Display* glfwGetX11Display(void); * @return The `RRCrtc` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -258,11 +262,10 @@ GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); * @return The `RROutput` of the specified monitor, or `None` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.1. + * @since Added in version 3.1. * * @ingroup native */ @@ -273,11 +276,10 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); * @return The `Window` of the specified window, or `None` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -290,15 +292,116 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); * @return The `GLXContext` of the specified window, or `NULL` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); + +/*! @brief Returns the `GLXWindow` of the specified window. + * + * @return The `GLXWindow` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WAYLAND) +/*! @brief Returns the `struct wl_display*` used by GLFW. + * + * @return The `struct wl_display*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); + +/*! @brief Returns the `struct wl_output*` of the specified monitor. + * + * @return The `struct wl_output*` of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the main `struct wl_surface*` of the specified window. + * + * @return The main `struct wl_surface*` of the specified window, or `NULL` if + * an [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_MIR) +/*! @brief Returns the `MirConnection*` used by GLFW. + * + * @return The `MirConnection*` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirConnection* glfwGetMirDisplay(void); + +/*! @brief Returns the Mir output ID of the specified monitor. + * + * @return The Mir output ID of the specified monitor, or zero if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `MirSurface*` of the specified window. + * + * @return The `MirSurface*` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.2. + * + * @ingroup native + */ +GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_EGL) @@ -307,11 +410,10 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -322,11 +424,10 @@ GLFWAPI EGLDisplay glfwGetEGLDisplay(void); * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ @@ -337,11 +438,10 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an * [error](@ref error_handling) occurred. * - * @par Thread Safety - * This function may be called from any thread. Access is not synchronized. + * @thread_safety This function may be called from any thread. Access is not + * synchronized. * - * @par History - * Added in GLFW 3.0. + * @since Added in version 3.0. * * @ingroup native */ diff --git a/examples/libs/glfw/lib-vc2010-32/glfw3.lib b/examples/libs/glfw/lib-vc2010-32/glfw3.lib index 014458efed8cff308e876c22c2e4832c705079eb..348abecfa98d6cfad9db67127eab8d5c72473539 100644 GIT binary patch literal 187376 zcmeFa3t(Jzl|OzblT6c+k^lh;6bMjW7E0PArJ>YJ<~@^nHE9wMN=Wl)Cgepj(+5(Z zJ1sB{K}CG6_^9l<_*x&hi0f)w%346sst9#?h%T;W+tn_zQk5nD&pF@k{oZ@$5zssQo^!tM^F80^J?F~q@t%Qq&bzF}dM&MQXk6ad(0F-+6<;e~mtJ1Kd>O;n z&(k#9gPL~7d;U7_-8Gu_|8A8Awx;iCdAEO)X4CKR)0%CzcVf9_`)j%%xKp#e9rurS zX}13#-6f|!p#9a|!CI~4Pkkru(n|gs?~jGGl0Vk{)fcsrzpT5dsmtx`s&%=X{y@YP zjRoV*jq8Wp<9*%9KKJNIvTsweX;E{tQ!@x-{^npP8jTU5r*EjQ2%+2Q^R+};y#5Fg z`umdc@zI{<-rn)Pi3zJnk24sI#^NrIhbY@Nc8>+&@%V=BA@5adtfXG2D-sI@qMo3$ z(;x0?Zgq7Hr-qV=iSFUCp*}0E&l!z-TH?VLFVjL+*92sD^&nc~qeHpGF~8pv3;3c+ z@K|C~-%wZo==gAVP8tN9QFq7_2}k^jxQA1WW#=VX$mtG7La{(gSdsUScMtciOZE5n zjdxA7`d!w*gq$%?I2`bJ0xIOwGqgAZevd2YmnrStl-EiEdoD8G=VUHwC;iGjko7k7r5V=fOOWN=wBq-$(^v_FwkLfkH=FYNb5 zTOu)HYpQE%@O6Wzx2YjH+SD*K+6`!QtZ!ufP~Ebo`re@-RSn#3r_1LL#3E56Ppw6u zYkYKFY9cw(H(@Y&oW5AZ7jXpz6P3suroM?~BB%zF*Xi^6`YS?J-hMa+Be=Hb)aw(7@6MYEf1T;=hlJbb^ zr@9l456usk#4Sfh; z?`YpdQ^Uw8eD59`<3uy_2HkS$ZfIsf{D^@)ly=_em<9#=#`X)Gi*QF3) zWP@V$H9KPg_!;nV<)p0DS@r5=m`GZinYh#Ca`~bjKWoVd>Wv$f zg-SlRZ(UvMhx#`*k8}@hzDaNS5P41DEeg*-dyrJ)qnq7ALmBwsNFr&x#fQ3+)Ql*# z+?E;}8y!a?OX)g+wUNwmsNr;RlQL1jMQ>82)0)2V;lv0Uc@8E;9i9W0 zQBlpk&*_f2BVLa$=Im(cY6-MA0$6?kCtM53n~mhpx}PajK*!{mjY=~n)Enw@S>(1#={7D>ZDF26?lc>GSc-xGHE zs7)^v)b637(H_+6riS%HqwBg2lf@Hr#{J%Ax62(eIQ3Laj8G<`J~s>}CMLMe=up9p zJA>Y+I~H+!bRAHj_AhM=x#BHBH=;zP-cOG(J$&@&qzB!)(4{UfN|!IFGIS9~ zkREP&#OM*F2i;0i%o%h=!){m1T~tsVG1MBILaFO&S1Na|?m3!MIJL=+9 z0Yx*7lhlDZ6nXafs(~yJFcDb}Ug3ZVf`X9}P6gNk zsLlmbF$fKn=-*t>Ez-RyF^se+=olXz8uD&HZO@GY0+#d+k0m#=Yff6U!j2dnFD$X` ztumAd3Y8y)kBs)_=9hBIPcJx$m^Dv~!P0JpVK$l*Tt!03RLm`c6hx$oIZxwpfs9f< zl3N(bpO?OhVof4Blo#EB(TxSOtFt?iESOz}!y}C9_7S}aFF=5v+K{t0=K>?+>uVeO%uWV= zMSs1?L1Wt(+JU_lzUUSrOp}N==xqrF-A1!w?#CDn(wZx9j7EAk z=lG4Vv3p1NP^wQQ3L5w*hN=8y8+q<;|#;7p5_Lv7VWIp@AbxgW|Pg| zJv@y5E7bEC3=q@;Fk*ZG#vY($dSh6N#@*`+`l7K=k?bgHdM$M|JL5sO-|G*#xFPjW zpt$vIBPdP}Zqd2*0a-;U>w#~gfu^`q*lnU{YXdYma948(m^RzK#iH5a@m3t zZD^;8YN6aPN)@bpGM5FEuUx#|W1`G$?(H6f0d1`%y2obH$>;7H81UW{t`* zBzxE$Y4Q7E2wfE%8KYjeXFN6B)X6uzwj~oiH{?N zuWf3es)=FMA@n3HA@S3|OxPDiZ?ApihLO>YFxpk<*+{n1N1V}SzsDa#x_E-c`gOep z7^6;%9JMq@$-EuMC=rI48)gtbj2&Vy1cTogK`QEBf(E4XI=rZ;E}yG8oBZ=2;d_!? zh*v1Ss59h^`eJ@xP!+DufxbTL06dI%pT{5d28{CRr=dDon7aJ!K~I+}l}wVs!7uSx zhlE-;H6wNPm(Avvn@lflL(n3qrObVm$>C}f{4N0p;akugn@*|9Jecn2Nrpx@Pf#sF znIFL`Y+SRtu+n%E6VSN@$f()T1z8$&lP1;On>Y34>Nn^<-BqN^Gz0}KcAZxm>N0w& z#nhcuz$}IYsQJCF-(o-18u)&b`B1CyFgPq6I(>cZy1wp4gT=u2)b_7fp&Sf+Z-0M( zPZ7KkCY^p=zmTD~&nx2INYoXKc$}V%!#3xz=AnNJ0d$i; z;BOB5F^04$K{~s!YiU<)0YWt8(V#mT4@aD6MQ92PddU+HHe=+|+UmP74Hj~{n zd>-Vh-#IbRgDzfv5ecKEcE>_3@sP83<8b#_q7VtDRFHvaW=!F;Bn}!cZyX~qac2_N zDvARcr8yL_Xv~YS#GJicWLM;Sgn{&Mv)k)JL`AV)+9f8wERtf*mS!IeObq7hR46Ez z9?PK$M}6TIDs?(leIcq?G~~zBqF+%h&8Na3o7?RT1u*TV$~y*Skmja>z7&a!X0auP z+EsKUsHuTixVkelhk1-}{L0OZpy5&D1iA3oGnd~{dSwR!VEJ-e;_-F_qieja$VYEi zAn1YCA@fjF-1arT6~6J&;Z8I@Vm!v&R0tZwjVOu3Ok-*eI{L?{aPnD1=#mP~%jQ4(&4FYoU|duUvuE20-Jiif~> z`ue-ETtY-GfGmW~Kt(lYsF6^X5k}eD$xAJX7xKiMzPT3!e@z2+7Gk}7WExojHAmD! zCt_(qwL?Y6N7*75o|#ASh%#sJj!^n=iwLP;GY{1f4LrAu&=D?YV2)5|#&goajUkS8 z-90x5v2d5^VIDt|oWg|*RS_;u_abg$xXmI;#MI^NL^<(y8ponYR zz-Vfym!p#tc_ZJHCxj{{$26*EiJlzHv*7abAE8jAdqioB-HAXM@6;&rSRRvc1*cjd z$@twIC8-E6k7LCKn!K>HE!9Kzn^kSWh(zO!{-a-?9@*5huJ8n@2kk4GV7FJ14kxex zsL))h7vnfFR{)lnk~)+qA{Hy1$es;*T~0Js4Om`5%9%Qx6N&Yh(Z*^CZmx92?so>D z*ganKUwO_-AAi?ZXj!QPPM@c_B@hXO^^k1r-aLdUzrq0zI3v*DE}u7=8<-THewr3%^uyvz!JL!e01mLh3gbT-Ks+N}6fCbk4xtw>HNAs!W~{!! zV20lnaAR`YO>yk+<7r50_vL5=d&0$FGmV;Jv548jD27U19?nct@?gD~SOI5EAcHaD z^tWKND1;>=oUlktWLx+6csKH7BSkAYisCRajQpXTHLa?GVG{`XBQ6ZS@G_yH(e*Up zi=|=+^O&6eH3m@zl&6^X4P#(|hGva&ZXQXI5!NST4MvYM7Hjc@-Cj>_F%YX0b4q~` zSdR~ub1>lb1u%CjX3SAfL@Q(}{XNuy;UZ}G2~I3e!ont0d&Q~OO4E|4zD=~21r@@~ z+S2Ta`rH`tF<565(Et`Fc>@tI`qgVF{fE0pkRPJBAy23nCTVF_a`PCT1KlQ1gHAtY zftv$ZB4Mp6vUZX>M%CJ)9VE#aWxl+BK)#qb824_=dJ z6RDm74uIh+)VkZ#5{1HrnT>uu`VKeA1Y+d?E?q11z$h>nBUpD8i$dQxUI%#=$htyF;?OCz7L?){XF_NHZxxeK3*H%8V5K z+JRB@iPVIMOd%TZ!H||h>jE%u)|W4quvV!ijLyoP9Z8knHIfd}qUO>ogVHvJQ7{aJ z;FWtv^|i~3j5<=UDSx!E{&LZq(p^->ndXdS2FXB(@l`8M&t=0BM%GJuWq}(gQ}Gy2 z40n%jmZZvam9qI5$qP%HLnsLJH!%-KVFN}ARc5$eU@(d6iN(SJFO-Yki5`@L+?Kwx z&OpnMLd{sg(`+y##N-vvXPW!lIuF#3*BkSN!fu17hgUAp%m__QnL6n@Q_vZYg`(jQ zmM^K04Ua-gLP_#;KtZms6GLt>OsTmHE`6CAObF>|zISn~vuk#>#KS&=?}k3;789vy z_yDC+U*N!n6|>M-AmpXVB3Twq=*TFwCuY0{c98j9A9T+z>{xYUCX7%5V3`l~Ik`@< zH*GyM|E6Om;#m93Yn_1+^3B{Jb6MwLig{c~qeodxaO5D>yhaY*Qr$RdB!OC-B;Prm^jRZ`qduUjLiA#u+BeaR ziy3`RUOkj*vV`bRohbiRU1Ca!L>wpb9dg%Y=~6hIRIN1?qI?n7BqiT;Odc(jt~_K; z4nTk&w>(lLW**Lzpm}bh_~oHFz4hAM;*3Wk&4EyJpPMx^?IL2WI?MpD!G170ORNBRnrrk+Sb8c@n$!6KR#kE_KO zHtXN+@%5O5v8Dk+|C=$kUS++Z6w)$qMnn<>ZK*c?yxr! z4oeHvWL?o>b?kZKUPWp|bcGEsVQ71Tv0w}KjOChTSXj#ehVfx=D^B!(q7gsV#WZ`T z=ahD#VvJ!)Kp5MzLg)_D@(40GWmi-T!*kWs6`yXMs+Ct<=Dp~V8%s3gK)TWcIRood zF~xYgtfI_qE!xT?)Cbou55nk*qi{R1L5la*mU;fhguv2!CB4+J71ow66(&(?QgFpL(Q zSiHxQe=Ok-MqJp*BcxKl2ev-XE^f9G!w&GqqA(tenrSHnrgqcN0YPtws+Xy4&f7;) zfDciTM4#W^61| zqZjB#LfeS)-A5}r(O(kF*v-iZZ^9ldSB?iGP8bAK|Ho+1nnrPW3lxnQQ1@ls_~;GT zG?2^d3wr!imhz%XyL8?=+rrAOp@C*^UwremI6KQ#=x(2-v2>3BLh)SybHW;z4 zrkicAK6Jhl=3x=6XNg3xb1M=wCzVW@{74%fV*QKDgAHz|8n7e`{h=ahm0@9w2K{JG zu)7Fj1&Usd!%;`pQWi~v1sDOvHl~;-;B`_TOYV5GQtO>lS)`P|7=-b8n_aOOa@H-| zkA^X^zmU44)X^lK7(w&~oNkPbhJ#*gBN-j%y-$tSy2T|zXI4JKnhpB` zm@vl%EV<>5N`a-!U_3M)bNM_N;N;!5qCaaPL4O(}2UsZYF_T!U2{I#qEjex&z$_++ z_7MZ38!UoiPH&{e7mvm;;cA4Z(T&9cxpYxKw)jL{R=S8zCyZA&cPM=>BxZkNy{^V5 zV1FfgWdd8A^f?KU_Hz5FWE0U2j;Puy5JJ%#NMi#QDR}h4U`AQik4ki2_r1_AEN&yr zo3C^PB_3^K){gqbk>$(lSI84b=4+bvo;x(HX1At&ugRuu^4qkh!!~Vs!lvE%fKA)= zW1IHCsU=!%utd8nQKE%ER-(Q5)e`MNo2EIm`Py9EbNH_u?>4^Y180NF9NacM33l+` zad4Thl`!50=r~}BY92q2)5;}B3EqzbA8`_$4K5XopT_Q5Yzeb0C{ikYaQk?lRm2lbc9W^RogeIgfo8zr;`B zb})V({B|JDrTDc$?s4*uQj}ogq2F@LALSXvQvajWD}fYxmdP*>L?I)$QvA)4?>Y~? zi#*aXf?vc($BAD`Ns6KIC-Srmp`$#qbLc4r=oZg;5*9I~m{1uJahc1pD+e#dlFD2; z$8#>bi!`8^i`Y|Hq`VV&DjkHk$@o}PMwCgCEB*wJ@uYMWQVA#0HaB&3UgMYYzXBo9 zG19OpzQlKW%W(SX#hKfUf4)U+N41LNXqGq6_za2}uY*R*Gt=WL{^&;c(VT#B6jR7Y zv7m6qv&~0w1jkVeIGN3~J=Xcr9p>5fvFMgMU&L(fOM z3E}7#*dFbAildmE(L2pYxrXM|W_+(XMu$-6Y1J z{@kEht-Lw8JVA~5jHYG%Oob__wz>KLurpR6*=U39ZOx9eDrahc7TU#?@=?g!r4js}DESPq>z zmd(V+wrl2?4!n7rhrnmQ)bkh)hC7CBMzcCoZuYBEk7e`fvFuQv)hT$hp3Zn%CUa+f zV&5?x5jDGco7pc;K88u_qdqc1nirUz`m@h>AH&&OZ_5FUvz~}MmL2JTWee4h<&etR z?*_$E_t~wFpXC8=Z_CR1x94nvSuaX)&;FFVSs%4Rr?kxapwn5N!r*>;&g46WV_9ic z%k1}P%=Re2S?}&}zYXgc;OAe>!G*Kl{4(2BV{g~7zW--7>(D^_?2e*5mXnWG4{hC=<$2%u{=zIbef`;v zTAA5uyg$ZqEHhfuH-q!h-(o+U>|4+1oUXsTHH0$sGdcr)rsvyCdls4U@Q-;4&h!i1 zm6tO+EN9w-?xn059jQ}0qobce_13$lgtte1O7v{cq?F#d{%EI6|M?FWl2Mq=@z(jL z<>jAI^fn%%C)euEe9LLk&oUHRIV_eFo3=~x?vP^pQ|0zIv6k5QW`jT<`{7Ocj=5a< z)-wXJyt%*ufmWKL=LjCd4qGgIo^}tkzBf#r0!S;HX=BVR4%E%tQ%wjX!Rd`Rm0P#% z{E>H9%3VNQB6wR+&QU)4;&a-`sz-hXyD<^=(eZpbx!bnD7G=2&@2z)nQa~jCU;0T@ zTsADbP6ejuI)43_GV2ah&Ks*!?pD+SBqEJu_F1`wliHwfVb-gs+<{rht)S#WI|(ez zmgBQ5F0|PocOz&XLC$W30`Ayn%sXpyoeCFdJw@QTX%l-cuU_K+_@|A+U$r+k*H`nN z_#$rli2$Z(=-cZ(d{*s@J~v?5%#rKUbVn`Z(&p|OF6fS8j|0KQ4i{6nJEl3pkJRxj zPPzu0D5R#t)^dX+2nv=MSwCSk1?Ei(&I2_fduk^}jY~Zz4QscO| zoJ=wtNCCXv--PJrbNLGGfqRSZMc}*}`q+rlG$(oZ_ck7dwY0 z_j4Qixix>j&qRvwiifyp)Q3>Trl#MVtg zE1N2DaFuX)iz7|N@fbQOb`p=OkNS{Dh3q)OTg*2?ppDJ5+H`!5v1Xuk8%<*JOf!i$ zsc?zOIi&-hPj{Y_Ud{egXQ*)R#&YJ0ZnDY4?vDD1BhxV=B5M%C85ndjb#Smvp#zdE z=A9&+&Z?6nd_D=6Py`~^vNO?`&w~M_wBuCpbL=|FsFbNeryF?2fltt7a+|ZFVx2tg zcSZCNGo`tvAZ+6GFZn!P>g|ij>V;PsfRu8D>^_0FntOzs{V~3OeW&*nIEDl*c8*@L z9#f*5h$6N1H_M@5Iobv^dZy%wDtso882-RXnU+(KO_e-P&U9x5amhv?WGViCrzle? zSLyL*J4M-IQ*#h-#DO}|fHO(iXrgfCo<_(thS4mDjCW;3lW>vQ(;dcqSXu2 zI*R1b#I(-nC`{)*EIyJq9m$|PhHpBW1ZrSW_o6Y_z{g(}=9@NP2^y6w%vU@lJ)*0^ zY?tX-BXg)&UM{VzUA}yIP0iB!gE$OB24sGZY zZ<;m%;0xvYoBW+u1v)zQXi=N)auT%wa#35mz8Q-2y~l|7qpk)r;t3tFRcY-r0>;k?CG@p=kWku+q8nu0(c~#OC^Op*26$(iQ z6%<^>=w5?c5;Ow~nM_-PpF-((7V!1-FkOYx?_{{Q&X8{X4CpAnH_w3XJkWh&26ShG zZubo6sEEEa13Jq7*JnsqMV_0kLg`2P_~IGRoe8>CGoU*Obnlu09Tk(|8PHL&yK{zg zpDsjKK>z&<=$@3c#q_BM4$pw*^m7mZT%;}wl~ZcZzb9#kjxJ}F)0x|z$ALeS3YY0B zM7I|1!v*MIvRvlDG2HFpHQ}J^igSl2HuQ{*C(pHFQ>jGn5}Xn`Gjyb_!`-?jhc<>U zsWnHuZRggI>iBQmx8iQrY}|l*uDEv1rJbYWH(cvaBm=2+*OIw=?ZkKw1JfGDS7=wB zpdn^+G-}gEH`vr~B!T0GCr0~|H5avBToW5h(nqoJv4|R4X_3HZKsBvBdua8f_lb>4KAWxe*c>reG_Fbuk+4hRo0YU*`(+&`nezc-)SN0cc z_hh|q&<|-{YJnZvQamddT8SrV^J)#FC|A^oj||i#M{D$x_iM%yoBD=o#F3^o>Vr@< z=O-w5=|h1X;MVH?H3L7qlwOpsdztEe=isB=jrbi;{7cBy-K{F zt-n|Ed-_r5K#h)CAV|*9-xrGaMf!V$Z&!c{tz3#WQ= zO0T-P96!mE23%H}jQ^7Ks@updH9x&-8v&Ku9>H_qvsS|GyDGPR4*0$PS`zrmC-9J& z<$XFncu|Ked__ z&Nl%5JX496mouHEcsZDfmE-MDrn3TXzs$s{@OB{6S&g?>GO-1C`_D}0LcIM~CRUT_ zT=YPRN`nV%1ah3GypLrzu1N27`lcd}R&GD@f2XFh-p8N}mJA?J+5nwLcYvU*cUN4m zDivLIyROSd-l%&@IFWit?aD?Tj(4nP473JBEEXc@7(K>zOvfL;GVA@9j!c!Hf$;RB zrCoJTJxu9%o$_W5-lzd|Xk;b|MdVdbDp# zGvSfIU9F&gKtkRaAR+G_K;_`7*1o8qZzbT=Ro=1(Zx=M?Ti1?^R?uL2UO@iFK)vcw(Q-vbhH`w}2hjt*@XAhI*7wI2c^ zQ>R*c5fB+E4($LS!SQQAf&=FnN{*8N3EYJWm(wudNY>t(?wSeux-h=)WN9BnBZ5<{ zYkJ2MI8U~QzH?K9Z@<*wLr8tyWH;WA)U& z*Y}^X>-Bx-iH3{JbdgpAfS{P^d4E7Koy@oaQ>#~Aw`)&Fwt8MIgqs|!}rKyLNLP>#e zXk>MXG`|GUGR9F8Ot*t2h}gXo?*eiIqE3QC3oG1eK#LjIsc>Bi>IHNWyACScjSAYJ zpmzhJ`sdKn3Ww3WHk`!Y7fwvzi-vgP`2#U6N3S%ygfH(l_hOg`-(dm9gK@xQpFZmX zgq)oeV^q1e1brH|W)%6oeyDEQ5`5@Xv%DZ2+THXpUFQOxBT}BUyi{MD;v$78ottnw znCS$58V^dzIaIc`9(o$!4su}|r7gR*sw11KsC&FKyQMrcdCAn&RA#ak&&J~`xBVJb zEbCjea(A*Kds{VLGTX^1``)Vn>&C|&)cB*coR#5=>ejK zVnlTIXFpEUD(vcjlPPceKKB>jV{>wJ6jD{e-R2S53d=+33RUk0+gtWgmh3Ql^!Jj}y-W|0 zD_>L&7rY-1_vsGV_fpnmzQ#eF{2)aOFO&dTE>W#H{0}^cwRbW^^Xltm27VXqG0TI7L`&T>#$FqP0$6-KGcKscm5r*t2 zW`gcyK!WaUK%&mys-W*E=#xl3;rfq&LM(*}laTTRAR*;BMfbXbP}ns;bIb!II2HmD z9Lp4x(*pMK2f1q|pfahywlR?$s8QdIknLKH9Inq*g*{k7lk9s7qKUp_%>*=TPqMGK zK>J#tlNR@RsEc-#Tpl+wiCG%bme7pl+1sf^qEwv#eMAl8UPd69wCmRHA#*|`wG z+oV&lWbdXjPX&+~O$eyy;PM2W2gU&sU?|H$y_8qLZBQFTqb|5oC+1M1A}C@KL?)yN z0X1Xma93-!cy{AOsnfG}EI?{~v?F`C?$yPw zCg)C_d?ivXntJ^@RmTx9t!wQb(y=1=WMK%1N^L)G2j^NRr!zdu9?pE5#7cuId5ZG6 zf_$FS=&Mha)J>&VZGvA~at=Dsy@0xqtkjNDy{^_y!86xCr@~RToBZ1`1b)QvOp0If z)VOd$p5bk7m#~x8?%6RWsLl{&gcBoqyqP%lBkGr!gF(tf1mhe)luOlYVhJ264uO;9 z5FHdU*^tQd*YW7X9@3X$%Ykj3Q+(b;}#`Jop{+fRDqWkZ|%igl< z@ubvZQ|<2o2;*3!IvH)BX50yQ3LK3A3y9S2C)t&9T;MKL5Sh;RvFlQWyIet60{SSs zHY*%e5+Q|*=nt{0p$j_jK8(9sy9Un>ulBsR(Abo<+@Y3J_?A! zMxSu|CwJwG47UILvt$vphSJYt` zU$;z5bknCx_0A9tiTd~>Phyc+Vgpi#9BI*qzQzNwCzPdUBtNzxsnM@e3n(YVhc=44 zkT|+tx6+b|9Xn^@Q>#f+jf-L;(e9{4_^^Ic{$@8{9 zo;rPi$Sk%e+vCukJdT>)v_MNZfc{ZI|Dm8?Dac{d=_(bp7|<6%;m{fY34hsU5ko08 z-ZqTd%a8HY;Ny-pdc`bWnQ9UfHToCIFqlJ?;R@Y2l@)4cGIioY@|wxYq_6eBP!b=) z!myDHvow=uo}sdRT2xXTP|yCG`RjrauJP{s{$Ci z?L=b1_2RvOrwp#=Bp1pTSiogGw}3E{c)C_0+x}z--dvwL}6$ zBfw7GDNhc?(QZ2jPrCl)>|eg9^I$GiauJOHY4}^etl_Bw+HRw8(p7%p;_vA^nzl=F z5e>LZGv8!m+HHiF$pf89b;X?Tl%67{BxYf2*^dqCUr5O(YBe&1N30<<`E?S@G5d95 zo?le5>^53sM7@uDd;isE_%)wY2`*}JtZ_dXSi6nvTe`0P=u>YRabG04h{noAojAMg zd}6_M#y7@c;OT+CPI3{Am5Xd~yX|6P!IeF-@Mi|sMALat_Mve$|bqZ zVlFsq*D5(29#h=UCJD9xp5%GsN$)qs{YJ@kwvuy~l9L;r8kW* zlB-6^d8(+Kb3kvmol8&LAHC%Gmkl`wCD%DD$DHp>Z$lC=*CSuq#a8Fb3DYM|O7`T%VF$L}TT;khv(8=sNz^S3YlW zJtet_#>#aOFm@ZI30>~QBM%r{C36IpXsleML+myxS9F~_cq-)Usd2gFA{r~#JAkp< zNW;*zrRqr(C7o+TauJP{YcVi(8)*i*{C|`EAA{@Tl8b1pTx9teT+f~IyLTE~-;-QK zW97P(xk!`K6*_ItA%km5auJP{i^`GRMm3tQr|+rwu)(#sTwsaD%5@nqb{n-Ublt!A z;x8Ip)X$@fXsledz}Ri1&FH##-B+RJ^)$>%E~2q=Ed|DIBh5+Ina`Gg&*1vD}AVPW_tRV%Bs~&aG z8lDDVg=J3e@93|-&Vj`Q zX>ff}auH35_Dj5Vt;ZZ{?y!Nh>v{i>I9Wv=E`_5vgYH0c2#2sb(IsoDYibaK{!I-@ ze5qAmn}tu}l1Tc%wNvZr;lq4Pp6DM|#zC+if2hSD^Lq+OqX~U{b`@XYl~ei<3vs;r zB=6IriQ%!XE^M9d(}g3b0bigw90b(yaK#D$eDQY_AMO=v0Gb*|ILqn5 zmZ#Ak{S9Y{^o%Fg^_gPeT)G^tT@!s6g-;|mW58(ihD4v{G@}OkdTx*o&U&pYF+uC+ zMkjC@&gh7jXKH#OgI4U(ra7dh9`YHTcouiMTrT?XvEPZY9MinGdhNa{YiQPiB8&r`zZB`y!rDuwac5BOpx;V$^{@<*vRC zJe$L$Wz?{%%u-sH>1pLTh7($GQkp*!_r{|wVZBBbuKXUi{IvZ>RijWCP$BhH)=%fj zJv>W4!J)u5QJL3BO>axE*%SAvT5S#kPmLiJ#oSm}#X$?R$p zA2+R=VK;b*@~*F(F%*+JyNedfD1RsP0_B?B2ZHcf0l(jaD$9A1H%f0+Vn_3pLiemb zwlbSfm$>l7q2`#&6Y?8z$QjU-gOAqO9OZZKLe7{c91eJJ#4+-xi>5AeX9TSBkNWF! zNAoq$S$(wXC_X|ui|?n+=5ulZzsD8imJ`L^DAc0%Ac@UQNB$XwQWqV=DaF3oA2l3x z9_Fxl$lL?qYYF(PTn4llGD?^NJ7%}^fgqWt7r$csSUXA8+Q zja-04I}P2N--51Ec9rO-(5@BgjXou5h>xy9yMw5oc4!84)SI8HcLhlpu0ryN?$SbZ zIq`^rZZ+sWC248wgX57yw*(pRZO|M#83eefqg9CR8sM))@9)F7>7s#?LUeK99|z58 zl!3UY8_RSB%0U-s^c{`G$^nY7wi$GLq&%W4ChsZGykMd$RIW(gFF~`Eh755{CvPQa zT1<3>hXzr7A#nOd}`)5G&%^Ar1320t<3wc?{`weJrk%M-{@;3;& zM?o`R4rdjsN52ML6KIyy0Ki50!}*qzE*{|Tsli+rZn{)?&Y`1n`cjRiZ8(Rh#Mo>h zc~Q810yKvtol55%d5?f@-nrNXh?_1N@+%~71o-mv;4f~vN^uvWdjCzXctQr@aW8N{mv`RV-a@g+jR$G+($_(5dzBwj z%~z?w;v(~;Q21(qzlnx>O;@4zV>#Uab_R4PD%!q6bUE?e0lMFV?qhYr;}h{yD14N> zv3fzHKMRGAvUN)#x&r0&bD;ZYNn5O(wnE;cpgE;M_^R5EocyJF8IUxBvamf_3CFdC z=yK9!1?YxA_ji(3mHQljG4Y{2Sx80B#m z1SORhrxX3{x9gOE+Yk=dEKUi?Jss;V!{vBkhEq+%1X8i#g{G^qd2T1RGToYq zys>@PEp^#Qd0R*J)yglWDzf{t&83xJvMv73N9!J0{K(3^TgpI`J(AvC(UN)@=MY?X zO&6a?u$zCd_I~T3PeJYu+;W3nM`!lGv%d1dnnqKk zf{n_r?;pf&{o8IP*Y<50@11+SciFTW;NC}tXs`DHEStyA7x2W-mr2fE@7M6061(MS z=SlX+B>NE`)Zpc6d8j}q9QMmCbIAmYLjy2w)}ZB?Iu+ zv;_t$PuqkCg*JMfQu(Eh(z>bbKfI+g%Mo`@2DQqE0=Dc2DM9X>SNTx61Vc99r}UQ+ zyp-rK_U!SMU&6jOj$o-DyV+L$?&fb~IY`;|^6ZwXx?P#=V-T3(oo|`#wCOFgeTbh) zJh5mvGf4!Kle9H%b>>_2llh>D?&Cx!V$zo7K3Dee)Q_?sq7dQ)h0UO3vZv zA1upH1=@m^{SG#vU2}j^NZ)^UF<^&AZ7Vet)!G(3FJjz>@gybb&_0bPENDQV$MbxK z{t3@>aaU`5@uWrp`=9YV2e(7}HJ&vL{SHq-XSbol%{W?&C^()1M15w5_Ox>S6(BOQ z9oqi@TENg0AR*<15}g-^@zpIeAEqJ3t7(4_jk`S~?y;gY zSkB(8)6lk-L)AMFMp3Vj&ym-%I7K9$X+MIj&v*}IyoYfp$05C>MqXPSIh1Wbvbg+(Q|JsQopB zTNJYFme;atkDy>K-g0R1+QaE1w&bnpBXg2BrH_;(Q|Tk+$+7g2(&UxtBW20U(?{&d zvh)#0YI8PPu{c_~_`8|Nf#`l+(udssgOm-E-Xp`-Spq!q~euz+$k=ItYPCaWb1vnX^t3bBX7|9j5 z9qef%LjgQjFw};p2u#`3C*PPt%5PjewP-uAXkBiF3GlFupLTv`__>Xr+v$l7`$Ssk zqE?4&D+l}JX6Q;hT?{$#Y-WgP=*^)~sG1lG<4MM?12;@aei{!-jX4@xE;fA!tLmPc zdgdeBcWo}?z0QLtOg+<&H+%ZKC4(m_xU_Td+Noy-uc_R51k}gv?IMEm>#}>U;eC1` z$P~U2B(4&qv&LHm{@A`zj0*b}gA2FS=|c4Xf@u<}3;Y5>vF z9Y)*deOYP(Y~5Rx^&VKIfi!vYs#5wnewB@W=Bz5iPwK4nmP03|7QF5~%u*{GQ?I4w zJ&a8jQ`eE~hucBK(C!0O=aYu4+*#@kRZLm7C@7c=WzWiemT~XKQ&a@_ zf&De9>OoC~Ro{+Nv8O^YP=ES$%aa^NcxQTHKcfFCUOL4DIHp!*>Whe<*->* z3q74}-=B3ETaq%~{j?)?0Me{R5jKM6XjdwtQeNa~9PWezv7RSf8#dVP=NyiAvK*=I zIy0>ABn!iQ@WRY|>tIo`F6^i+=l!iKL>Ypwwt+fS=+>!yLa7pFFa&BM6q=V&L4<`- ztY={m>Jgx}fcGL9){fC2P>~XaYXp!ea1Q|z4es{V$gbxD+Q85yfF>Af1T@Z23!obrq6#ad^aB!7=-eC%1vWAPq9X3lZU!Xk>EA1e zA|r5n0Sz+Uen3KsA19djxRw_)d*t?Wov@B~bLSI}j^IF>x8oMtnRO1{^o!a>v1O0;+xzM}5$@B9DvR{DdHZp4uG&stB(mJ> z%PL?*HhcTED6gXJhd*{|`yaXoa|CT=NEKte=d2gi0)v;)U)xy;}GFURd(O%?4AQ) zqmA8z%QD__a$5?w_NvzGKIw*V(UEM__hVZ5^4;ta$y#&pERp)6qciww96cRQ_`w%f zXOG~8>w72E#BK1aRqsOzrZ#LaC$ub)B5RN-`uR55+c{$lM0!hwmaNEpo3b$T33BYZ z?wYlGsMLNKw}U%G^j6JAl7QCWor+wwM$LzSl7K#h+o63N&kr*6RR!$`3;hQDNR8&jd11-2Y~)C$92+$mZhs?FMNR!8Pzh6!rJ1@TC@9Dj z$}jGSyoOqki5x}~@(pUO&@hzIu`*@fptcHcr#AY^lP9Kc(MLBb9u^%1{AjnYMiXnc zU=L^84~g_1Jel%xbt?#z`mKA)dL)_X)$~JpcWAWE2@_I4|)vPF9(od;re0iHRLIEV5rQk6R7*WeZ>bcnRf;9aEjmjH>B{%1giQ#$?F6eU2Tw<1~A=&ef4YxGtp z8ymd~lJ%n6nR_`1Df+gNLxZ-(`&zT@uPy#TYg`nB)o+#mq*NZj?cnhK14C3MOrg4D z2i}EIicrzn9tc(CHVQjJR=Mpf0K`dAliug`p4W5!aMoX6_xQhUjDwIm!TVS4M&XX3 zaQ`zKV!L6%#bCjqD5Db`g9T?U+ie}KtK-yV%iy>`svxf+clEqEv>2Ax+UK*WmlyA` ze+LHIbKa--r-bI>YJu+ys@6LD+EZ!Yo{F{!|B7kkOmAFnAT7~+1%MlxqAf#)J z3=^GCQWGMPeg?>tNR}%8C$1!>49R+{vylbzaIbRYO~qvU^GFbp`>pXzM2_WUxr0C& zfqFb@?88?-TfKvdFS3J%xS)7m|F_JkXo2Qry@y}lpRs4XPeWs)@`0g(Ol7zh7MJohq0@%;`%td32? zO?uN$rqs$kmD}$F74qQh#tG=lRY(}tm&gZeVw1LPuSUhPM;2g+$=<$@s#p80n;?_c zgv!Jq+iL^WHjG|AhAzq>(nZjkuj~K@`JZF%Me9Ys3uD@Cx|vr#czFABmD@gz$XJqx z)c4Lf#3UQfpPH(jO5cLR59Xl!YPTP(q9zg`CIDySI!eN*4LSX$zk-YRG)dt@P6bh~!}^pw!htI_<3 zD#9VBUO9(+>egvPE<8T&vDJfzWx3c{3)ZZ!DjTh@dv5!#$`9^gm73o3CPvpwk*GqW z;^maasM4s>9F0oGfT`wF>qc4CY09QHk!E^96(^(>>aHzAqKo#e36Q9eRQNBleGhlF_Io^u0tY}MT2C?*03}uK zgcLtYya>S{Ai=v4kWv`3{b(<*d%W>)NO4r&yF0sE9AflC4v1N4s0v>RCyEIlI;C`q z#rfZ+cYcwbcYFaqQe&|hAw}?!K^;s|jpxr9!h<*c(yxB~41gRJDJQ#BD&SqoOK47m zV>B5#qS}06pg!k4^1=dXpg!k)127EK3P^edw?iXSm5Me;?geyXxSYR$cI9v;CC)pB zEu7gphUCh4t0rM)ePsx6HbV)hH}~jFzyQ-Hf1t?9AyPD%WQPlgY>h_timbl>VyKu( z+xiE))2^kOL{*yIm~PiWoS-Jsi0ZvcEqAv4K-T-R9@>?xol}=?{ez9XJTtpt1#DRd zj!j&B5Qnm%x2H>qA1u*9XjIF@jnRNDLA*o*Mo$sns{m2#9o#b!&@kRb7EpikH|+XZ zJYQw#Yk2-QL%Z-)B{+S^JVc0d$6<%3k4z=YD|gm=!(}|+n4$qkeaH>!A$3CD$;X2* z+@D{)`#-8=_Y*qgIks$_0~KH%oPrereKGLL|Ek_j8TQhiP2?;M|94VE$l9-7ZXv ziV~yLVR@#RlJk@Scw-&9qXW};Yzsa7DRM1zodo1OB%T!w<@S5=+#u)^BNQkMk+*grOu|R#Am_Kab(*{TMr&@t)qgXt9S)H z9f1_Z?s7n)3dRA6D%b@`R9_nT6V;b`0w-{)k_Hz!_aLAG6%<;qO^$o-r-7j73JnBd zB!fy@zS#qj8ugq2OfJkSXtigJH zuaNKA`8126k}Gw-#7{3yc-%2KUjX7MSr8lcaxNln3{ufRt3x{nI8kIn1Tn4?&^T@f z+XCk>j(V1YZX=+x7`Fuw&FNM1nQ(NZxr4{wL>5u;TFAIh0y=}C&j1pVKM&}1#{Cl@ zA(_T>PG#JafKFlPhk#CI=qG>#Z{A2NZSJh;8A^<;8%6!duRy$Mmku#qKQy|od#Gjr z6$xXpbo}TvT$tPD@mqXCmJUrdMs9ad2B{{zP%)w7y!EW$!mvkjMnmup+_F03;Hel=M;%JNTGN zk<2TBBdgWHgQ$Y86*!TpR|686Km&E67$g8)3XW=aF`5NYAZQp`NTy*b;Y#|6M)w^& zz$g63%Tzu2H{$cDHP$>>k)OpnwaQOExSewjp2_7p_=T^0T?~K?GW5jC_u2`UUiC8l zq;M7;s(DA}V5zFltH^=V8tX)!Wgz32dN%!NRmN9JD?#?!OF#iOvN%N~&ja*Mj^xFF zRxw1a>Xi(U0wXKhp>?!$wFFw}!-M$z;Dr3pu|(>xLe;asD0k0;*J#buHxsxt(Lgo& zh!s%S`_}Fu+s4nn91lo@>r_B=N`blV%fuI-bF4{>P*c;>S2LWLn4qFxD2O%K4BIy{ zfi3IWh8wU~&iXN57AQaP+D-e~<#trWl+J&}Iu9(G+EUIjLR&&H;(BrhV~p=WAWmJA zzTff8EY^e2;tKC!^v*KgBlvs^#tbj|ufJU>Y6f+Ty|l(c*y*sFF#`1l&+m2Oq|fCsnWLoLAwp^=OZCk zpwnKKTE;}^V|282O6^4>7LvG>h$}&S921vKLkv?myQMn)W@Y6aHz53#+dA=_^!+au zWmMj=1(j18fm`1_#(j(92k1xi|7mW-ra-YSO@u%ZlZB%w((lIDLuLBin5CGjBTF$c z%fX}Kb{$RTvV_Jn$xupF>E6!C{zgP1J%EHlJwqj|p#$1aC83!tVKIy*hz4y3FMwgT zm`;dH|E?r;F462|P6##88D5jAe7N%KM|S_Js-sf`NdHYgx?m;&gMfXz|Ff!c=M$AX z_pNT#BL#~?MM}q&zOo3x-TJ16XXPDqa(LyowT!V*7Thr(Pq-4CzK62|%a*Du@1PZB zl@B3rRjw$BCSNGBmD?WyZT7pIX2QyePh#Q$pECGi-Qyx9Tksv0>TIeCg)sfZ6q0}C z6Uh@B+nmYy_U~r`3$iUv`}Z<|h1nL5a0m#8nrvIZ{!Avm$mFHSt;+3G1^d%ew#w~p z^4>kRss#C;e8(y(Gs*L^*Q}s1stehzRMrM-LD#zvR_x^MZ(_Mf`bbsf9sh~QS3Y#7 zNCT?u_+Cxb`G?VexRfl*%55op*d~3znVg$GP+PhEn;_r>;Q@D3kn47BeUthDl^+B^ z-36pXs$wg=AtATCF*PNVtwT@aDib&L+_zM>X7`Gue0}%S*}LDYdL6A&DHP$>|DaVY z>0jE|HNEA?n^2g^OSey@0_iPPRVi2Y2o{WX46Ff_kj}4HsaG73Eb1kX5R`Ye>gQ9d zIu1FPq!whi9HEb7$pQ=G9b<+aod^FJGnC#Vt(_fmoQ_szd@1`ZN~f$&l{>#*x$}`s z1X{ZywM5pn4?v4&A6uNIF^lw}s>L6m0gFte>N$+mwO74x?V@r(2j@TMt$?d|t$tzQ zA`t=ZYF5Cb^f!CKre)I1&B7|T|LhM~8u|g!l-!W0c7(b!Xh>-M7L!lR*Dgo@pjh^% zNfZ)AjL2FQ#N_Q$$mmr+g=^&&N~ostqSl#DOv z=5ZvUa<7-7Ax*`DCtz#|6QDGFDN$S&uok5%F0%_wpWv+Pz zY-#S+s%h3&P9ZTV3{>E6O7Dst87%G0Y^e|i2J)U3A9iHC)dGR>IaLZ@GY7Zsx7(*~ zX+3Di`e%fUMCywMoP#B>V9EtQk_|GkIt<4icj_PO>J+uPy}C0~`c*;aBfXfaxcNaU z;9Dy6yc6^J7)W97PM!Q1C3!Ydovr=~)-Z#qbmi+e{~A0r;ZI(bszzG12Ja)D8DFKP zr8eC9RRVzGn0MLHgxKx)7gtFknmi`hs`QV-I;Ug~U3PvJeUuh;`O`R*9gA4Ue8hJI zx3JCLk64P&D7_C*H4h=(%@7S;OtNbh&|QrCh{8P%h(^*KyqxMV-m1AiW|)qKs08k8 zK-90U*4_a~xKdw47_@Of)c>f~Qh<6G`Z%C#7@}oTx8ttXXjSQUhG?978$-|HDWtpt zNJycE=5N^bBxsMV3{ma64Uj{lPl?^iP#>Tz?79sQrAW2*9zf*`{VgEsA609I00}?N zg;^qoYE~%dT0l3kydFR_*Wl201EO+RtvwD1pR5G*3qb9RvzO|w^og(}yDnEy43J3i zA%)wnpw9skVL1S3f_WP;T074Ewg9@3adhV77~?hp8fEBpK*J2pb6{T^LzRF;Na-|3 zvUaPrHb6qkWcPF5A?D{o@+o^EB2DFUhwg`1*Eg+O8f|%D2Nc23f0(33o=qy4J z`mCb+h@$(V!aWG+QucQjAko!-7SJ_}dqLr(GV(ZDQP*qPr8& z2;=DB_yj}m1JupXy@0M~=p%rxW9U9WgA9ENP!~gg2T1sfBsN{wIk^*C+c8)>>D`A$ z`^kOk89CmW@xClH`+)N{nxnv+Q$!z@ zf=Y&;g9rOx#hXKG#q&PK(WKr6#`WX*QO4a3=pzh$6wrqmx*yQFxbb1u+}$MOee3a| zHhf)gBTnuc-H1`QZhVzZUq9J}8sXMr{AnfXueS55I8IVT$&NWGS~gpiZqkz1WY<== zb?WoYSjJVk?LF|)gi2#a1-4b#Qnm6MJUX%XA}EAQ!O1lyF7(vAJh$r;6RCq`dOx}7 zoWEtpRS)c(u50*923^;1f+Oh1A$SQ+l?(CwG*YUXN2zx(6b0^646Ok~U5RQQbfrozR9Ec4yPOBW&&u|yICrAe{n$rDp&WE*J69R2rmL<(k?!-BxL_J1G56x3s@r+zev@861|mn$gs zt?a5V6Z2H%HX6$1)Df}=K81Ib=cyl6e*N$O1#0)ND(Pka?t>UCNS%4x&V5J^8%87| z2Ud58{z)ebfcc0)c@R7;3EB^|wzUmV!BqrXZynqiypGwe#$O1P#0(UelPmccWQ+o3&*r)aHyp`a4*iAfGWphLi; zx&fl0+-hm%zXF)L_1fpz6ABeYnSs63jl&%s5XnSQ}rKClzb-1F2nYd_g?eC5}@ z$Iqt^M56Ebli@dhx&^i>dVAVWhL0z$C30Wnu2d~wV=q^L{VNPnK{GtpobPoy-_~y+ zkUFNTbnvtnjL~4knJ>Fmqv4EX)2?80v7Y>D=Tkn+r#PdT2hFKMg!XCQmwkq0k?3@i zQLbc1p5(GT$&__=TSQ9!@>f=^HzZ#mv2%oE)6VE}=Aywo8pQ0Hn*Uvct4?y23og@s z<+;ptwsc?k&=+nLg@_PM5=%7JGiB!iW1JJbp=$r6!S!y*MKn|#g-yx;9s=_N{gpB1 z)2XSTimxIN$u-}-a8&2P*-C`MMKnUrxi&`dLtq*erY0xMD9fQc0%XfPM*()USRCkopArWsOA@(BiaXst?!RNT)L)N_>4xa#gWk zi^9>RguVnk!|C#p33mNk7$I*Mw!)vsb-awzQA52fU4<=4L# z^^4j#t6$Z5@j8WRK15I4|FiSgh#tj|uK$&iPhr2rVWPr?p2G1sQLGs)Fw_s!FKgML z9J1Tecv9Ku?b`RRhF|pE3c5~J@d_z9RG#TdD2(p=Z3?5)+?R*>x&>pdaSI?*=tGh} z{PO*NBRt=iTnkiqerlCt%G1+W4wWlC0v z1FgP3L9kUa)l9pMv>9Fh_79)@k}d`2u9QPGLNX^5Q|8K{sXV)_R=U0V=&MTpZ5(;z{*u^RE^>XvFl_Qu2Aq zuj9z5k(Wrr8imPC!$qL8+k$wKn3Z2R6FS%?c~?lTMM`qJl0#`|u5stHoL}Qf<@GaP zX@EM^%+vfJ24K$m^|SQw0t)YbHIWzrv@2jb{m~1NLJ41 zt(07iO3qbQIVRhN#xJZkWMf{tvyy2@(~@70{7B$5TM)_>5D^NQqJrR0=RS5;o3WG=|V zTx!9X!~9Ng+HLpZNrK<;`z^mR{PIbzcPhWSEON-xEqRy^D@;vJE>mA$d{NB?=;yW9 zf5Y(Wvy!Wc{W6Ep$y^jdB02vT@w*MKMr;Jv&kkJR0W2FZcDR3iBZy3PY8VzcQ&XRIT{nC5531!gim+P*F#}LDLjw zDS39Y#GtQd>aDwgwcE%Bx8XkJ^fT`_;$A1i>=JP|ak-gGFF(Kh+|?O_D<-+z%mqSi zy(R8u->Ht+ZNI>?8ut&cX#*vNgRYw-mq*F@m_-iJJeY@h%7QWX3%sDW+iLKn>*;Ur z`=*{Zn)VCHMKmJ6&YjO>{1BMsd6-BZrpJOY`|g7z;~RZ#cdS38`-C|m$wf56udfu9 z<7YYV;Bevm%6X@ybsqF4Bp1<$QJS8y&62VP7<0-8Sk4YSsV9Hoju1Niddlmal>n!_ zITk_YA{&FQ7k~LlRBjPsOrIPtutXzpYb8d@lM@1s-FB&9(2{?+74JLp2jV;ha**MKsn}tOmwzyNp?Y{*B$=o_zioSu6 zOn#AsQZr^5S-{laQ#5tUf%#j7Ar7CCOum~-cqd%#wsIm;m!4l&NiL$Xa$Nd6+L+FpyJ6M$(l^4ltKf zn17Gkko=uot`$fy-nT1gC|*m!M!jFcAaQZMVBsQ6DRtZAB}(g=3M2D$=~84ES<{B^ z%@!JBf0x4if7HDRe3aGIKmH68hKRvL8x$?-sHiB22_XmqX0ps=Aei!EEJm;Qs?!G+tIrkp67U!sb5kkG5N8wMz&*S-EvpsHfXs(N-{W$yJCxq)v z_;g==|4nS^sq{gQLvxWv;lA&RogBY*VVsgLMyS_=NkZJXsIHEV{t#PSh3yACv>qi7iq>BoA5-d zm{4zl63f!qhK`8iIk;Y9lvT^h&Zf%{tnN{*(^1*g(%utkjs<9QPr}L~9g$e1 zZuJ_4H4W+o17TR;tSql6IdojS=e4L17rh2dfhw{Rx%xGL(a*FQ*WDL$84WEB2FgoI zf|b>@8+fRq;5D)CDC&{srrtUru3iUW&eHihyTw*64&cGUnE>546jE=8k=blG`DhExy*5FP7j>gw&FRFSZ> zt*Kiz&c%@pHPMz{GZHWYvor=u#)2Fc_ipHFPNg!@7O52jXiaJ1NaXUGNN+EidZVgn zX;6qnW0$peMgnL6P0gR|L#wNa!k{Vc6LvHRjZ$S?ij$e_HQGd?+10|)-oR|uGi{``sVov8XqFH#surd6F%rP54aSx?ht#m&u; z?pUb3BhqWv4vlQ~M7tXU`KEcz{P|TS;l-7uRh0pD%W`_v^g{F+>G5Y-_{1Pl5~?V# zsH?0ybkA5PW0B(3#U{3HHLQA~N_KF4V_=SHY&E|wP+3x2U0PCCI%PT%-p-y%ohYZ$^na-Aova}cKiFV?i z#CamcSlNO~>4|Po`LK%LiL|>+eWWwGHloVkY%|NdObtXOqLliFTDEFyHiZh4%5*k2 zZJ9J}5;&|%0?2SU6Q*b!O2{%^2x(@<#^PLMV@m8+u*@V@|LAJ5dY{-GHhZ7sp*q@i znUZ9pmu`R(W@k+V$6}j%tpqzdluB4?f3l)a4MJ;BTuasX=qxjf?Qmh$?Vas0YmBNv z{VAF5Azb0i5zjRkSTVUrUuR;F&`?iPXJmC>Yipz@O^U3X2$?33qJwma)tbu8B4cf| zwEv}Gm*RA87(D=rjm?qd_jO2yH} z1Z(#dWGsZi?y{a}UssDxvo&d!@YuUTE{iUUcBeELtI+Kc)GRK=rdl8dL3`wI2AHKI z*2GnSmSoKX&I(i%k^`Ag%~oBE+1_d}=3>JvRmG(0soiF)>=jgVN}d#bLwj%gYP)k* z>VnkhQJBmMnoU|#Cqt;RdIdJL59>t(%Q?rg0QsfJYHnVEDO~I(p?Rq z+Ja7OI8Yg^Ev>65Ei-BLr3bDSvl4~e(${Ua*Ji29)U>%TnMiZLgqg&$xGqt-MjDp}LZ)+S2Ocz~L^oFl)_h5#}mZwg>c09%h|Y z2db-TgTckY(U!(?`2$kY*Kv6hdRDI~995!lSUg}rbhosU%0OjpO-WTvWff9u#a}Sn zzCc2kGiw>5q#>z6Sr>05Udb#|?(1a1KojutLaRm(zUPG6yV`r(tPxG7>@vLLm^DV4 zC4G^e4fZfElY)ikD-vFa=3230GXQV3(T)yakoS&2UXnBMbMgu!&LF3Rnke3`(F>a| z2iBUHn!00sJ&v(QZx)nlytzh@OsGLW*oD(crif)dP0g2!WSO7cnO5{QQSLA}Q=;CA zS;|T*W-w>4Dsma0*}?GYk{Vjpr1p%YM>-Zo_M+Q?bSz*6n|^KUV9;yT)M#ZzrO{>B z2x^X1Me(A5GA(QG#VFVX3^FS%2V|;RBdsb&Y$}dwb@P{|Fk9u5ywDS=XrJ!)wt9VT z%q%_YtB4l^-P!pP3OHpAgT2yGh_L*;-)<|edmNzANGd8ovWsGdz zVMoJ!v&}CFVlfb^DXpt09`$v3C3{*Wy;6F0^lItxXZGfFLxnDTGpMHN@(4f=jhG?|gaIERE&WN%F$zW73eV7cA6kcT=pn&01|*(=nR9+D6hrR@*ld*Vxn^ za|<&1;?G==jFDbI|g3exg{be-|GrPSJb4>8#b?>(PPcpHZyUA7_3n&~yPKr^LAvPBgz3 z4T0_jP0MfR>8v(R1AaWx<#b{_(V;WNFz$z+1-ki~mPt)#W%gL$OF?syrsE%pH;ue? z2)t3#9ZKG9pt(=eF+1t3G4jjBcR}+^GF_T@UjfYlO=rf7y82I9MZ6kGFZyS#BE~v; zXGK@9fhN+zqj>^$g49%Wt;hOX(~g<0H`*HWPp?1AU)LSun?7&WDvfq_W3=i)^!ha2 z&>ZN|;9}5Gu9e%y!Wzm0%`R30Kj8R8HJgR+ljA7}1N3qD_?8Z(ASwo^P#MCVR^H4d zvwvCjQe6Ah5?K#g)o=yS9zTx2@Zusy3*!!3m_&U(R#Ks)^YfdX3V!Xu*Je02N2lXA zFgbC^3wbArEPaGoT|TR1u(6+jpU-eb$LuQtCh8<1fG0TqHQk8-CK&(Ovxe;d?DMsG z!RPI7Q&3tE$FqiNU^qi#(5rxPeoG{+eFkpp>pxjyf1BbLemc@XQ%M#Lf)GzhmUg9) zknHG(OqW{+Gxb~}t54~*v7=UdzW8@L7uRd4J}Vbr(-{77#|71iq_})3U-MX-DlVqH zDD#}fc3h7EL&r0VDqr|uX*u_IR5p39hb@GZ*|$B14}=~~`1S^A!t13&=uUE_tSyYG~ z$u|{i!LqEQSG~cSbL_H6PiK17@3@fz=G!qlS+x83W1uYPq%Pen8<{reHSyMC^=3l2mnvryWG)u`cKbj>?cg+ zJKnEhax*)Ydqzt?6CLl!i+jXYa~yjXJ3-m<%yVqX3pH1UVUGM4jw(mZXe>4MwpS)x zfE9$9!VQ{>r|{i#lbYkW*f43;Dg4g?V~*k&=h3cv%%NRIRkha<>A@YsoxCd*LoD9v zyP7woyfI-|6m}UK%`rBay%Zl{umdqFvnAe`cy4|{o^xT%1YO*gilhJyVA=q9p);Mf&qEOhAL5YIa3(lmUgOJ_s= zEZ{e$qjTuilb0>(KG40WX<5JN#%i9c-UFJu*=6CFj&yXpfM3M!>2T@ju3!2i?iNkUCXp^)(hY&;$A_WILGSJ#idK%DkNwv z=w9T&2uBvm`wz~Y*CGj}|Lok^sdQuh4bvxYSYCpQka>9$-m&_3l&SlvkJDjm4_&cu|-4!04{8VdRDI8eCD1D+NE$rdM&}RfAj7)(>LnBB^P1^1{2SM5*BdH z+lsVNi(g94Vugd<8H1nUAe4A|#*67Cd?p8x)#Exx(;x;+N5bwg=V!iz^2Ib)uB_r5 z?UPeN7#M-8fX`;-lTlL5-plaJCa!GfvXkY?70_(QKI2;W?C?J0Ir!{*KG-*`G?wBn zpK7C6tWT!AemAGRVSXO#kH)9^zqgEq6`P6z!4<{0s3{cIuie8pNDxAC#T4Iy)vGcX zuRX98bJ`Z5v^C;j=F*0OcN^O(Fb2m5E_{DvB%U`o@GvfyZ3q|qD*o*jV!nNe_-*j_ zl2u(0#flvqBq?rU8WtW(;aySL*C#;s?!ZA@o9T(o6X}C@bbuc=_C$o-gElxo6mAR} z9Nb1R!}4qj=?jbuFiOqMh)nLpAOo}v2GA6hI|+T)?w>e3z=X4u+%n>KTUl|+U?IAN zWM9u)?97JvDap@PPxkfWfZduA^TqFG`Sd@|XmBy=_pF!(RbG*!RSbf2>W>^LX znCq}R*V)&98Psw+XzAd>yUE(9FB}~dsY?d$V2cn4#xcf=}ctmyc+>_0O(%EX(hF_@Rw@lJb2$ThIxtR86xFik1(C8XX| z(W=Cvj+07u;G4J+H!;ZaOXS|1@WqdfXWX2S7KpJUK81I#J1^2=_wnQBv^=mF&(O>U zZZrH-@ynI_%@oA$tsq_^sG!FHscoU>0A&itU#(DHilpS73rNuw0aA3;Rw%EkJXLtV z4d@hsbgvxztPDC&HV&>I=P&~T>ozlnpF0?rhwhWU*9toe*tHq%65Fa|35hB`YJr$dsO*Jc1x^V$MH1^B7U zACDBM2L5dPa>YQ=A##>=?fNXH6*o=C{B7WHTUSC-3Vx!pfjPG!k%ux+X?;^j@9olSn|6L$N1p|t1kgg&@`b;LiraIP4*SOf-KF!(X7JUl2M zDFaj#%}rrpG@eTvWw7A_Kt2?-Iz*Z~7G@56qcUH6;2>me!Oxuk(elu@!|Db@G`QgF z8ir}L2GfY+6wD5jSIXCgBrCmYP`D!#UD}+ShX=xVqN%`b91vRL1J!s=92Kv5IMI+1 zU%m|{54|DW#Gd61!CLYIiCWmK+|hq9yJvj=!6`ixhJz3I!KaorgCe?qu-shR;3CRt zsZD8RiYYYIxuiFKBiBNsR6mFKO8jsWGW?kW&4FJb5c{&K)@DGefA0jOR#QI&RF0p| z_&I#lbbb#=aj@AdC}myO8;SYXLU$+X@1z2{jJjDM-vVZ9)D;VGjRhlm&}I2HhU0gC zfJrm{xPhnm;~DfX&}}D67gVDfgm;CPVi0Dz>p>VxvZaV4{`f&oyTJ#_{h(|=L)08`z+jmvu@_HoqfIIc#Rr6nBj%oO%@CXQWj z2lLi=m{PK<$6nweit`o~; z-pyH)?7cnbP9^Eotug|@L(<{$#aEufsIlCMsk3OzeaY1p#*}03IWhoyj*eXzwd0wi zITrk7^?s8_T>;Dh(x}*fqUj97pCo5ILexziBpKfF9)>B!gL?%u7ikpkc$A28BFC}Y zgVhS;oC}{M4;=qLFWV)yNORfW`7W~LP_nb+xijVUa6gTCo7ok^+-4GAr2*bns?zgW zGYGT_^W_wbY>p$GPSLz*(NNBzZ_&&Im)EmPxN)D)l;Rb3dfw7<)Hg+EF8J<_8;9Vt z4nD}7muGWLQi;I(y_pO40n@olgRRf&iNj|dhH>qtxTH!V4)Ugr3;?5VBU#dNm_O>&;s6dbATBf;pTd9)dzPZs^ zKHLek<=k;}Vwx@IN-ZZ_+Q8v4Q`dZ(X^~pe50HLRO)N$dSd@rxoJR{Vxjy%Y(si$f-6ebkG<@iqK;4P6zdHywu^?F`(IKhD<*aBdh)57U&X- z#;|Ie4i#!AnY#**B&+m9im9z$igS~-RTZ`6;b3~TklqN=A#W5&6kaKu9fK-lO^ySr zEI6j2v@MFmAXbE_6<`HfMXlBD&&{7(=y$loePPU>n?Gm1&{NNHk$honn2rnNIT*pE z`@(n^Cm5$2T;@E*HsR(oEFVM z9}ZJ5=umHtwJGu4_4 zc~Wml^-DWbUjp3Hfd?GJRK6*jZujxk1 z2iMetpz&)>R(64O`FIU|4&|#=Go*Dz) z>7Y9>2D+)BJDQ1ixOC;b6$N$<=zc*4I6r^*0-xLtu15t-#wNq(P9>FLuz1py3zqxF zXP9Y+3*-b+#&ObpVGMMv_n{QJ)OmsO?n|LdAMgERpkut>Nuf(0?{`z^(#N}NjC4Or zN0-#!ZbSNB0A0&80C0T&m-dsJrsxbM&5AcEzfAs>p!uSvLpM#^PUiyu5NP&|f$l@l6tE-1 zjV5mv!pcF@cNn@d(8WRX6HUkVn67{D!{v$7;W^xB<+l)Y)tc5UKP=JyQ|BwLLz2t> zStdNym;i%oHZ^#+%LpYxf`!}%zG&u?|k z=Xpub^OK&>PkLUE^t>?XncKfk`PkKTJr^ZC2a=wPlb%bGo=cOSIUG3S3no2>lAgOO0Q}IT8G-EJm%f&QP;*-}EmYL6BDp~qI`Q*ZS#HH2n*&=-Mfs$>@ zCkF@FN__^~BHO$AIM1HqlTSE#0#UyDQoRfi>%nJS2%k0T6FY)z8>(d4%6wu`knI)b zGvS{jPzQYW0iUtF>+-JXx-S2Pvf1WW`zOYQtE21v1#|OoSgi}UFm>>_S|cv=!j)IO z{&ayRdrx1de{p-v(9h+4?J*pRHbbd3?GHD#n21nE`(=YB^gv1Nz`U6*clr?V<*()660q0@JGJJ=3#8zLN?KXX;79n z*JKXL7f4ZMdJ`Z1NHFpuzIYy;`tf;?pD!ENWa^`9_)rPb;C{*#j>k?nLf;uvI?rEU4lGKNtTc@m~>t zkNB^PzgPSN@VEKFX)^H(@ZbRb@ZccjENMgc^us}hJWq)UoaudrlckanK za_53^eHV)c3UpI|w!WQayvI+bgOmmpH3rqUO@K7$w-LwrO39r&ILJ^oF=NTo!M|%I zQu%t^mmON5@_pSg_|8ieJ{C22jf-`0;lqAHkWy|xxpXh(P-&BU9!>c9M0InOKwHWBhCG80Su;gRPxm?_{?r85UpnrL-P;5TH|!w7&rCFC49yHLM^wVU_OYENU()Jt##8otCF?+l|=5i1v%LR#P{!$WW0}L zNG9S98J@l+mJdyUxFhB>ZUe-$!`?R_wS3@r zT(x|dg;cFZC@iR25XSoc18rM?b*SA8mS${!33URc==h3)dtMGpZ+s0Uup^~>%lBvY50BgL?H~5`k7RG0oR(;?G}lxs$v__%co#WMOqznY z6Gt};2DgQg!5^>5^ah`a_uU!BOatAZ;9ZGh6ID5DP96;2sq`uvq&Ut^lgAupFj0~@@@%5! zE^FG(*mpNGwfvq$@GfCmgZ!y!TPf@e&iN1o#*Fs{=lqpJcf8i02xr6_rY9;ghZ@j5@lX~b z?0<54eLR#Kubr}&akP0b1vJJ(Q&`v-X;+JbY4_|Q{0CXLGKI2{Z7=#hZ@8R6H@fpVf+9=Q|fK+GzkeZlQ1G-W| zhXAb?=s`d$1^P3fPJ#Xos868r=w?dFiGb8Zmj`IMgq{zmN1!kumAAcw>g0HHP9-NN$x5)QtKQ3s%JvP0Dn+zY;OaffL*sJvQ+$1>G*R#PS zYHsRoTHTH>p6!uCh~oDUznlz=CB@f_kH1!$MA!4clr2cU8lJX2n~AYw{T?GWsehi) zhY>V$enm#Cu7Ah8MN=>4=t+F7lKvlD36IalX75cD+djil({CtjXI1yds7Qtl$Qg4pO0#a{|Cj!!Mj(|#p zZU&$W1ey&KYeFw`lX|971Dxft>DZL1s6%@0kb6Nw}rY}9I1ibXt?z>~a?j8{TlAI6r{TRgW z8k=HSiBQ(l852DFwgZu<1)Oc{`zBxvuVkl6<2)A;lL^rMLj4c+=0Y&U|(Et1l_t@}z=K)J_`= zJ`-MoJYf6Ak31LwV-xa#vK)sz_<_ai0dV;9jt9qd@Or@aq>;(fGG$;odC@J%Z{Gx6 zx9O{PH;OC!iJE7#p9nr5m%}O9_x~XK{vFpi>QP&Kan zcb_WmD|z+hUr7dE+WFF7Ty=SZh!!z;`BU;<+xeQi!Y|6$pT(lseM};hvHQXdBc4;6{XC zeQ z)t6H_UwiAdB+gvnlv4RbZov+OiOvq=8zSs5^lO`LX& zO$T=XHjEu3zm~s*jjw!9;5`;@PZ75a7BQ^gSKs3TCE>$@;23KQ#3wHgGVFdJdmpdM z-p2vi`*=t8J_c*|md#>al|3*7in!PXKxiXolwc%PT^lA$NVBAJeoEODv7?0q`>#e3DE+cjv zPRsJ;S#8&Zum{!uQAW>Omr7EQjN3%s82gtYdaLMxI^!|9?FBJ*55>2=?*i1@ zKP_xZYR+wFl=|!6hy~_4sl_n!(!#n!Ee_j=Om(ls#1S z2dpx%a>au5`#>2p-qg#{M?H9wxUuXh~WBpd>3VR+^@cBB6g#P9`!Cn~QeJPSl16c!1XE?N}_9bMctI?d~JF-G1$k zb~NzdLcN>>|3!gLhfn!FIX3bOf#$(iEja*)4Kg?VyAUqz#x*KU%@L6BBeB~(kH`PZ zTW{E;+|H?`#^FKT0!EtqdY?i|W1-Mtd=*EUafdkH@!G4K3T&<^nv2|SuJORwan)7t zz1!xRrnyMt=Hi;q=6d{~AMX}s3c1v$BaNGj-OT11zW=jmS0)$t<>*M`=3=$mTn!g| zbid8T@t2M?ZmuJMvAJfpS75u&jH`hxaHMf_ak{p-F1qc(KiFIx=jlk}<~kA>n=A0U z`_LB6xH#0(k;cu%#%*(*_Vk2$n~Q@F9cjSj&~%&xjMuXR;u&_^Et-Aos=s&ITb#j>w&i?H%OQ=(nM<0}@Jp3*EUInXLogo%Q-x zSK2MSQOACQ;YSO1a(x`MUe9+SmVNLx&k;YexuTluuf(yX))3l=?bZXs8*>@wDlsax@Jy zcJtohlO=X%effopda|s!w*JenwYfg2Q|PzS-0w;=7_1wJ3A=0X6kxobGZ_GP->lz% z!K^Ku{L^ws5~a?p^2v$db4jx)G7a%{2`e zujh0{W=#ItMQd%YR?S5kCFx5VW1uwLawx&;VQZxG{qKSMO&+{dYA(`%%b^E(1~6XF zRuAQ&=WV>D*e>}4n(GXNsTl+d7Tou0s?OlS_{d5RC9}VCh@5B95W~Ta-|ZNeSYyxU zuywWz!vW|t7luR0R3`>!sGu+G!sG*UloKQNZMjV;`EuoyZNTfH&N0WGdDs2suXau+ zaoB-7(_l`WGb3x$wywMB$1i`$E>*wgB8|H)&T?^m?b#E5Yje%hT%>Vxoh@8ufi}!t zvC8HOYcA5bxn>9#*H?6dVxog-Xk3h@AE zw(wgu7irvFvw*SVs=T-0Wt;0B%|#k%KVn090cw!-C9Os5+n(gYu>HJ+pGA|OhvveK z528`LP=MV)~pd>riew?4})8dJY-~86hm0`@$T%>WQhrQgLo`RJ0u-|(<55cFH z2m8yn+v(}hlIN=QILe20tM0aD+1|8c(+_N}&uFgmQn)yNcs-1fTyMK?{^lK(KMv^x**ZC=23xul-KKtrW`EBS09zb+Q zO;CRqC@x3sEJT3U!&#MX>AANaVb{)?nu|259X4wWY2Ed;2pD&LEs*-U8XPMtE6Y|^ zIyaFTjg{rgfxNI7A3rsGkpupO1Fm21eAwW8xWe(Uv;!BP!1Rg8E$NHJXeLD-!gUS$ z5TY_QO9MnO0MXebmj8HU(Z+~nQl)43$)nO_ zQ6aP@-K4=lMM-UKd38nDB30^?MTMeInM@rjE-9<7T5QL!6fM(H*9NMBwV}H5P^BeW zG%%IOmCfq(scA7r)hwD)Z(nzJv?tc9QjU6;TXSLM3IEMwuLTvwp_01V%EbXF*lBr+ z4##Zko79nSRh^Yxt-463wasc@sI#AtAQ)*_mbi0+ER}*L2 zC{+3dD&wU%*}WRZgLpz&;hh+DELSuDMn8Kl<@8Ay0gjo)R9X?J3)WSZhAJupWtGV$ zRju9OqCyp8QDHP-v6jJ%Y)NrdS!Fs_IaO>jHDLtc;bNP&GEh=g8Lq1hp|_<(D_RkD zl%f}5vxWkTYbz>Bt6{x1mDLq3H&luWTM_MO$NWob0=32EW#x4x#c6~og$gSn>cRlp zrn|7c3%Bo=iSmcp{46VD-Oyq->ro6GgM!EM0|l+E4vRB+4qG&Ztxh9UCjIKxc|vbK z&&g}fYn`WX46yMnt*x!imTVJmBFyJGd8;E$^G$3rznub;zQC0#p|>qgb4azU1en>i z%-+g?>oWI*@z7=K$uzQ56{skyDyyijtqVA9D>+)8b51d9(rpSVttlxc!Ms|)OrJLD zh73AG(W^~@;`LCy88uYRIENt6rY0$z7932ex>(E!BOIs-VK*Gh@^)ik^APAx!)k?&?;q(-u5thAId0cFT)GplM~ z(b?(flKR^c(D9D`Wi40M#2NJp1ce$AkJ5Old5kl?t( zA?Zt^yBzq1ptzomX!6Q2 zA2i}eH<~<72~D86%t4o~KA5aeY8uL;llpM%Oc2NMB@VjJIpqDnY_A4JO=JItQ^ns} zeo{^Jt)Cse`A5dlsIojcb}&VsDr;h9f1YIeJ2RUr79xF!=Q|+wQ7X` zy5jP8h*o7rUL2Z^Kj8kjAYI%So9q$+As0Xl( z$%Gm|)b0pD?N0r9NBud-Kk=(SplVDQGN>#AC4?grWse^y2e5y?-xQaa#6WpkGUNw{ z1W_GCFkqbn7>YDD{bXV!w0>wFK+rEVF`y3s2ECo!G9WHCFRMkVaXC;Lj9j82(uT{S^Kg z0{sF$KQ-WjPWXzKHRTta2jham`2g{Qk#bg>PMZS7)ar!-lr7BkFMo zJ;;lWyM>+Kgfks5M++0Ld#KRs-beV-U8qFedO$5FF4f)Ds(tvaP_|fwV-HXedzpd& z7)$7hW7|~E6EFy1N?tS4#*a^XiEg9*BoWvI7sNL1#$VQDWo;`Jkl(i+ zEhZSB#IHl!*}Gd|B#a~+16qf!Ajwii@+p#V7yt=hWwuod$(FOh_00x91j3CEw-p;nTtQY1Wgy8U9n+s+Zh z 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 L?xao99RL3TeG$IW diff --git a/examples/libs/glfw/lib-vc2010-64/glfw3.lib b/examples/libs/glfw/lib-vc2010-64/glfw3.lib index 8cdda39987fe55d400fa1def0738b4bdc8672d51..768f3083660f35ca37ce0d02a2541e92eb5cdade 100644 GIT binary patch literal 291120 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 It5l%>4{5MQ*Z=?k literal 202450 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 Date: Sun, 3 Apr 2016 23:28:05 +0200 Subject: [PATCH 13/24] Renamed ImGuiWindowFlags_Force**Scrollbar to ImGuiWindowFlags_Always**Scrollbar (#476) --- imgui.cpp | 4 ++-- imgui.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f170b1666..4e4909df5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3980,8 +3980,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Scrollbars - window->ScrollbarY = (flags & ImGuiWindowFlags_ForceVerticalScrollbar) || ((window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar)); - window->ScrollbarX = (flags & ImGuiWindowFlags_ForceHorizontalScrollbar) || ((window->SizeContents.x > window->Size.x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f) - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > window->Size.x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f) - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f; diff --git a/imgui.h b/imgui.h index d4deb352a..39746e581 100644 --- a/imgui.h +++ b/imgui.h @@ -466,11 +466,11 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file ImGuiWindowFlags_NoInputs = 1 << 9, // Disable catching mouse or keyboard inputs ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar - ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You need to use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programatically giving it focus) - ImGuiWindowFlags_ForceVerticalScrollbar = 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) - ImGuiWindowFlags_ForceHorizontalScrollbar=1 << 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) // [Internal] ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() From 07df3cfb3e4ad37523f834f9b77a58a56ae1746c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Apr 2016 00:29:57 +0200 Subject: [PATCH 14/24] Added ImGuiWindowFlags_AlwaysUseWindowPadding flag to ensure non-border child window uses window padding (#462) --- imgui.cpp | 2 +- imgui.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4e4909df5..476ddf907 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3766,7 +3766,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Lock window padding so that altering the ShowBorders flag for children doesn't have side-effects. - window->WindowPadding = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : style.WindowPadding; + window->WindowPadding = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : style.WindowPadding; // Calculate auto-fit size ImVec2 size_auto_fit; diff --git a/imgui.h b/imgui.h index 39746e581..3d2e0277a 100644 --- a/imgui.h +++ b/imgui.h @@ -471,6 +471,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programatically giving it focus) ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) // [Internal] ImGuiWindowFlags_ChildWindow = 1 << 20, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 21, // Don't use! For internal use by BeginChild() From 947171dcefe691286f53fafa36674ca6ce935327 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Apr 2016 00:30:50 +0200 Subject: [PATCH 15/24] Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(): outer frame not honoring bordering (following #462) --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 476ddf907..4a32088d8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -693,7 +693,7 @@ ImGuiStyle::ImGuiStyle() WindowMinSize = ImVec2(32,32); // Minimum window size WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows WindowTitleAlign = ImGuiAlign_Left; // Alignment for title bar text - ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows + ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines @@ -3442,13 +3442,14 @@ bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags ext const ImGuiStyle& style = g.Style; ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, style.Colors[ImGuiCol_FrameBg]); ImGui::PushStyleVar(ImGuiStyleVar_ChildWindowRounding, style.FrameRounding); - return ImGui::BeginChild(id, size, false, ImGuiWindowFlags_NoMove | extra_flags); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + return ImGui::BeginChild(id, size, (g.CurrentWindow->Flags & ImGuiWindowFlags_ShowBorders) ? true : false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); } void ImGui::EndChildFrame() { ImGui::EndChild(); - ImGui::PopStyleVar(); + ImGui::PopStyleVar(2); ImGui::PopStyleColor(); } @@ -7310,7 +7311,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 return false; } draw_window = GetCurrentWindow(); - draw_window->DC.CursorPos += style.FramePadding; size.x -= draw_window->ScrollbarSizes.x; } else From e808b7cfcaefe6599b0ad7388980155d4ade15e9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Apr 2016 01:37:02 +0200 Subject: [PATCH 16/24] Style: removed WindowFillAlphaDefault which was confusing and redundant, baked into WindowBg color. Renamed TooltipBg > PopupBG. (#337) bg_alpha parameter of 5-parameters version of Begin() is an override, however that function may become obsolete someday. --- imgui.cpp | 55 ++++++++++++++++++++++---------------------------- imgui.h | 9 ++++----- imgui_demo.cpp | 11 +++------- 3 files changed, 31 insertions(+), 44 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4a32088d8..eb809f2af 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -152,6 +152,8 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337). + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. @@ -699,7 +701,6 @@ ImGuiStyle::ImGuiStyle() ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - WindowFillAlphaDefault = 0.70f; // Default alpha of window background, if not specified in ImGui::Begin() IndentSpacing = 22.0f; // Horizontal spacing when e.g. entering a tree node ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar @@ -714,8 +715,9 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); - Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + Colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f); Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.65f); Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input @@ -753,7 +755,6 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); - Colors[ImGuiCol_TooltipBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f); Colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } @@ -3138,9 +3139,8 @@ static ImRect GetVisibleRect() void ImGui::BeginTooltip() { - ImGuiState& g = *GImGui; ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; - ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, flags); + ImGui::Begin("##Tooltip", NULL, flags); } void ImGui::EndTooltip() @@ -3278,9 +3278,8 @@ static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags) ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.Size); // Recycle windows based on depth else ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame - float alpha = 1.0f; - bool opened = ImGui::Begin(name, NULL, ImVec2(0.0f, 0.0f), alpha, flags); + bool opened = ImGui::Begin(name, NULL, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) g.CurrentWindow->Flags &= ~ImGuiWindowFlags_ShowBorders; if (!opened) // opened can be 'false' when the popup is completely clipped (e.g. zero size display) @@ -3311,7 +3310,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_opened, ImGuiWindowFlags e } ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoSavedSettings; - bool opened = ImGui::Begin(name, p_opened, ImVec2(0.0f, 0.0f), -1.0f, flags); + bool opened = ImGui::Begin(name, p_opened, flags); if (!opened || (p_opened && !*p_opened)) // Opened can be 'false' when the popup is completely clipped (e.g. zero size display) { ImGui::EndPopup(); @@ -3391,8 +3390,7 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, char title[256]; ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s", window->Name, str_id); - const float alpha = 1.0f; - bool ret = ImGui::Begin(title, NULL, size, alpha, flags); + bool ret = ImGui::Begin(title, NULL, size, -1.0f, flags); if (!(window->Flags & ImGuiWindowFlags_ShowBorders)) GetCurrentWindow()->Flags &= ~ImGuiWindowFlags_ShowBorders; @@ -3692,10 +3690,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->RootWindow = g.CurrentWindowStack[root_idx]; window->RootNonPopupWindow = g.CurrentWindowStack[root_non_popup_idx]; // This is merely for displaying the TitleBgActive color. - // Default alpha - if (bg_alpha < 0.0f) - bg_alpha = style.WindowFillAlphaDefault; - // When reusing window again multiple times a frame, just append content (don't need to setup again) if (first_begin_of_the_frame) { @@ -3987,21 +3981,20 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f; // Window background - if (bg_alpha > 0.0f) - { - ImGuiCol col_idx; - if ((flags & ImGuiWindowFlags_ComboBox) != 0) - col_idx = ImGuiCol_ComboBg; - else if ((flags & ImGuiWindowFlags_Tooltip) != 0) - col_idx = ImGuiCol_TooltipBg; - else if ((flags & ImGuiWindowFlags_Popup) != 0) - col_idx = ImGuiCol_WindowBg; - else if ((flags & ImGuiWindowFlags_ChildWindow) != 0) - col_idx = ImGuiCol_ChildWindowBg; - else - col_idx = ImGuiCol_WindowBg; - window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, GetColorU32(col_idx, bg_alpha), window_rounding); - } + // Default alpha + ImGuiCol bg_color_idx = ImGuiCol_WindowBg; + if ((flags & ImGuiWindowFlags_ComboBox) != 0) + bg_color_idx = ImGuiCol_ComboBg; + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 || (flags & ImGuiWindowFlags_Popup) != 0) + bg_color_idx = ImGuiCol_PopupBg; + else if ((flags & ImGuiWindowFlags_ChildWindow) != 0) + bg_color_idx = ImGuiCol_ChildWindowBg; + ImVec4 bg_color = style.Colors[bg_color_idx]; + if (bg_alpha >= 0.0f) + bg_color.w = bg_alpha; + bg_color.w *= style.Alpha; + if (bg_color.w > 0.0f) + window->DrawList->AddRectFilled(window->Pos, window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding); // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) @@ -4522,6 +4515,7 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_TextDisabled: return "TextDisabled"; case ImGuiCol_WindowBg: return "WindowBg"; case ImGuiCol_ChildWindowBg: return "ChildWindowBg"; + case ImGuiCol_PopupBg: return "PopupBg"; case ImGuiCol_Border: return "Border"; case ImGuiCol_BorderShadow: return "BorderShadow"; case ImGuiCol_FrameBg: return "FrameBg"; @@ -4559,7 +4553,6 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_PlotHistogram: return "PlotHistogram"; case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; - case ImGuiCol_TooltipBg: return "TooltipBg"; case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening"; } IM_ASSERT(0); @@ -8501,7 +8494,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) bool want_open = false, want_close = false; if (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) { - // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers so menus feel more reactive. + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. bool moving_within_opened_triangle = false; if (g.HoveredWindow == window && g.OpenedPopupStack.Size > g.CurrentPopupStack.Size && g.OpenedPopupStack[g.CurrentPopupStack.Size].ParentWindow == window) { diff --git a/imgui.h b/imgui.h index 3d2e0277a..c4834e79a 100644 --- a/imgui.h +++ b/imgui.h @@ -114,7 +114,7 @@ namespace ImGui // Window IMGUI_API bool Begin(const char* name, bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // push window to the stack and start appending to it. see .cpp for details. return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). - IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // ". this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. + IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // OBSOLETE. this is the older/longer API. the extra parameters aren't very relevant. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! might obsolete this API eventually. IMGUI_API void End(); // finish appending to current window, pop it off the window stack. IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400). IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " @@ -546,8 +546,9 @@ enum ImGuiCol_ { ImGuiCol_Text, ImGuiCol_TextDisabled, - ImGuiCol_WindowBg, - ImGuiCol_ChildWindowBg, + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildWindowBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows ImGuiCol_Border, ImGuiCol_BorderShadow, ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input @@ -585,7 +586,6 @@ enum ImGuiCol_ ImGuiCol_PlotHistogram, ImGuiCol_PlotHistogramHovered, ImGuiCol_TextSelectedBg, - ImGuiCol_TooltipBg, ImGuiCol_ModalWindowDarkening, // darken entire screen when a modal window is active ImGuiCol_COUNT }; @@ -663,7 +663,6 @@ struct ImGuiStyle ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! - float WindowFillAlphaDefault; // Default alpha of window background, if not specified in ImGui::Begin() float IndentSpacing; // Horizontal indentation when e.g. entering a tree node float ColumnsMinSpacing; // Minimum horizontal spacing between two columns float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f85eda533..64c60862e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -139,7 +139,6 @@ void ImGui::ShowTestWindow(bool* p_opened) static bool no_scrollbar = false; static bool no_collapse = false; static bool no_menu = false; - static float bg_alpha = -0.01f; // <0: default // Demonstrate the various window flags. Typically you would just use the default. ImGuiWindowFlags window_flags = 0; @@ -150,7 +149,8 @@ void ImGui::ShowTestWindow(bool* p_opened) if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar; if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse; if (!no_menu) window_flags |= ImGuiWindowFlags_MenuBar; - if (!ImGui::Begin("ImGui Demo", p_opened, ImVec2(550,680), bg_alpha, window_flags)) + ImGui::SetNextWindowSize(ImVec2(550,680), ImGuiSetCond_FirstUseEver); + if (!ImGui::Begin("ImGui Demo", p_opened, window_flags)) { // Early out if the window is collapsed, as an optimization. ImGui::End(); @@ -211,10 +211,6 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Checkbox("No collapse", &no_collapse); ImGui::Checkbox("No menu", &no_menu); - ImGui::PushItemWidth(100); - ImGui::DragFloat("Window Fill Alpha", &bg_alpha, 0.005f, -0.01f, 1.0f, bg_alpha < 0.0f ? "(default)" : "%.3f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - ImGui::PopItemWidth(); - if (ImGui::TreeNode("Style")) { ImGui::ShowStyleEditor(); @@ -1561,7 +1557,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f); if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f; ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - ImGui::DragFloat("Window Fill Alpha Default", &style.WindowFillAlphaDefault, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::PopItemWidth(); ImGui::TreePop(); } @@ -1618,7 +1613,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) static ImGuiTextFilter filter; filter.Draw("Filter colors", 200); - ImGui::BeginChild("#colors", ImVec2(0, 300), true); + ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar); ImGui::PushItemWidth(-160); ImGui::ColorEditMode(edit_mode); for (int i = 0; i < ImGuiCol_COUNT; i++) From 2ee76bbff64656a48fdb43b76f2f8494d9448873 Mon Sep 17 00:00:00 2001 From: cheriff Date: Tue, 5 Apr 2016 17:23:00 +1000 Subject: [PATCH 17/24] Trivial format string fix in demo --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 64c60862e..a7268d480 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1496,7 +1496,7 @@ void ImGui::ShowTestWindow(bool* p_opened) ImGui::Text("Keys down:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); } ImGui::Text("Keys pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } ImGui::Text("Keys release:"); for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); } - ImGui::Text("KeyMods: %s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + ImGui::Text("KeyMods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("WantCaptureMouse: %s", io.WantCaptureMouse ? "true" : "false"); ImGui::Text("WantCaptureKeyboard: %s", io.WantCaptureKeyboard ? "true" : "false"); From 67b604412ba818165bdd81e57217584a9fed05b3 Mon Sep 17 00:00:00 2001 From: James Chen Date: Tue, 5 Apr 2016 15:49:23 +0800 Subject: [PATCH 18/24] Remove local glfw3 lib for osx. (+1 squashed commit) Squashed commits: [34cc3b7] Adds osx example. (+6 squashed commits) Squashed commits: [20330f2] Uses glfw by brew install. [0427861] Renames imguiex folder name to imguiex-ios [f9e27e5] Renames ios_example to apple_example. [44f8fe3] Updates the glfw header/library path. [919f279] Renames target from imguiex to imguiex-ios since there is already a imguiex-osx target now. [24395f5] Adds osx example. --- .../{ios_example => apple_example}/.gitignore | 0 .../{ios_example => apple_example}/README.md | 11 +- .../imguiex-ios}/AppDelegate.h | 0 .../imguiex-ios}/AppDelegate.m | 0 .../imguiex-ios}/Base.lproj/LaunchScreen.xib | 0 .../imguiex-ios}/Base.lproj/Main.storyboard | 0 .../imguiex-ios}/GameViewController.h | 0 .../imguiex-ios}/GameViewController.m | 0 .../AppIcon.appiconset/Contents.json | 5 + .../icon_imgui_60@2x~iphone.png | Bin .../icon_imgui_60@3x~iphone.png | Bin .../icon_imgui_76@2x~ipad.png | Bin .../AppIcon.appiconset/icon_imgui_76~ipad.png | Bin .../imguiex-ios}/Info.plist | 0 .../imguiex-ios}/Shaders/Shader.fsh | 0 .../imguiex-ios}/Shaders/Shader.vsh | 0 .../imguiex-ios}/debug_hud.cpp | 0 .../imguiex-ios}/debug_hud.h | 0 .../imguiex-ios}/imgui_ex_icon.png | Bin .../imguiex-ios}/imgui_impl_ios.h | 0 .../imguiex-ios}/imgui_impl_ios.mm | 0 .../imguiex-ios}/main.m | 0 .../apple_example/imguiex-osx/AppDelegate.h | 15 ++ .../apple_example/imguiex-osx/AppDelegate.m | 26 +++ .../AppIcon.appiconset/Contents.json | 64 ++++++ .../AppIcon.appiconset/icon_imgui_180x180.png | Bin 0 -> 5953 bytes .../imguiex-osx/Assets.xcassets/Contents.json | 6 + examples/apple_example/imguiex-osx/Info.plist | 34 ++++ examples/apple_example/imguiex-osx/main.m | 13 ++ .../imguiex.xcodeproj/project.pbxproj | 192 ++++++++++++++++-- 30 files changed, 351 insertions(+), 15 deletions(-) rename examples/{ios_example => apple_example}/.gitignore (100%) rename examples/{ios_example => apple_example}/README.md (84%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/AppDelegate.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/AppDelegate.m (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Base.lproj/LaunchScreen.xib (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Base.lproj/Main.storyboard (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/GameViewController.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/GameViewController.m (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/Contents.json (93%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Info.plist (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Shaders/Shader.fsh (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/Shaders/Shader.vsh (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/debug_hud.cpp (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/debug_hud.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/imgui_ex_icon.png (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/imgui_impl_ios.h (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/imgui_impl_ios.mm (100%) rename examples/{ios_example/imguiex => apple_example/imguiex-ios}/main.m (100%) create mode 100644 examples/apple_example/imguiex-osx/AppDelegate.h create mode 100644 examples/apple_example/imguiex-osx/AppDelegate.m create mode 100644 examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/icon_imgui_180x180.png create mode 100644 examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json create mode 100644 examples/apple_example/imguiex-osx/Info.plist create mode 100644 examples/apple_example/imguiex-osx/main.m rename examples/{ios_example => apple_example}/imguiex.xcodeproj/project.pbxproj (66%) diff --git a/examples/ios_example/.gitignore b/examples/apple_example/.gitignore similarity index 100% rename from examples/ios_example/.gitignore rename to examples/apple_example/.gitignore diff --git a/examples/ios_example/README.md b/examples/apple_example/README.md similarity index 84% rename from examples/ios_example/README.md rename to examples/apple_example/README.md index a2ada955e..c847f1a3e 100644 --- a/examples/ios_example/README.md +++ b/examples/apple_example/README.md @@ -1,4 +1,4 @@ -# iOS example +# iOS / OSX example ## Introduction @@ -16,6 +16,13 @@ Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImG 0. Enter the name or the IP of your synergy host 0. If you had previously connected to a server, you may need to kill and re-start the app. +## How to Run on OSX + +* Make sure you have install `brew`, if not, please refer to [Homebrew Website](http://brew.sh) +* Run the command: `brew install glfw3` +* Double click `imguiex.xcodeproj` and select `imguiex-osx` scheme +* Click `Run` button + ## Notes and TODOs Things that would be nice but I didn't get around to doing: @@ -25,7 +32,7 @@ Things that would be nice but I didn't get around to doing: * Graceful disconnect/reconnect from uSynergy. * Copy/Paste not well-supported -## C++ on iOS +## C++ on iOS / OSX ImGui is a c++ library. If you want to include it directly, rename your Obj-C file to have the ".mm" extension. Alternatively, you can wrap your debug code in a C interface, this is what I am demonstrating here with the "debug_hud.h" interface. Either approach works, use whatever you prefer. diff --git a/examples/ios_example/imguiex/AppDelegate.h b/examples/apple_example/imguiex-ios/AppDelegate.h similarity index 100% rename from examples/ios_example/imguiex/AppDelegate.h rename to examples/apple_example/imguiex-ios/AppDelegate.h diff --git a/examples/ios_example/imguiex/AppDelegate.m b/examples/apple_example/imguiex-ios/AppDelegate.m similarity index 100% rename from examples/ios_example/imguiex/AppDelegate.m rename to examples/apple_example/imguiex-ios/AppDelegate.m diff --git a/examples/ios_example/imguiex/Base.lproj/LaunchScreen.xib b/examples/apple_example/imguiex-ios/Base.lproj/LaunchScreen.xib similarity index 100% rename from examples/ios_example/imguiex/Base.lproj/LaunchScreen.xib rename to examples/apple_example/imguiex-ios/Base.lproj/LaunchScreen.xib diff --git a/examples/ios_example/imguiex/Base.lproj/Main.storyboard b/examples/apple_example/imguiex-ios/Base.lproj/Main.storyboard similarity index 100% rename from examples/ios_example/imguiex/Base.lproj/Main.storyboard rename to examples/apple_example/imguiex-ios/Base.lproj/Main.storyboard diff --git a/examples/ios_example/imguiex/GameViewController.h b/examples/apple_example/imguiex-ios/GameViewController.h similarity index 100% rename from examples/ios_example/imguiex/GameViewController.h rename to examples/apple_example/imguiex-ios/GameViewController.h diff --git a/examples/ios_example/imguiex/GameViewController.m b/examples/apple_example/imguiex-ios/GameViewController.m similarity index 100% rename from examples/ios_example/imguiex/GameViewController.m rename to examples/apple_example/imguiex-ios/GameViewController.m diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 93% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/Contents.json rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/Contents.json index a05a29bbf..06b60d8b4 100644 --- a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/Contents.json @@ -63,6 +63,11 @@ "idiom" : "ipad", "filename" : "icon_imgui_76@2x~ipad.png", "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" } ], "info" : { diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@2x~iphone.png diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_60@3x~iphone.png diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76@2x~ipad.png diff --git a/examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png b/examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png similarity index 100% rename from examples/ios_example/imguiex/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png rename to examples/apple_example/imguiex-ios/Images.xcassets/AppIcon.appiconset/icon_imgui_76~ipad.png diff --git a/examples/ios_example/imguiex/Info.plist b/examples/apple_example/imguiex-ios/Info.plist similarity index 100% rename from examples/ios_example/imguiex/Info.plist rename to examples/apple_example/imguiex-ios/Info.plist diff --git a/examples/ios_example/imguiex/Shaders/Shader.fsh b/examples/apple_example/imguiex-ios/Shaders/Shader.fsh similarity index 100% rename from examples/ios_example/imguiex/Shaders/Shader.fsh rename to examples/apple_example/imguiex-ios/Shaders/Shader.fsh diff --git a/examples/ios_example/imguiex/Shaders/Shader.vsh b/examples/apple_example/imguiex-ios/Shaders/Shader.vsh similarity index 100% rename from examples/ios_example/imguiex/Shaders/Shader.vsh rename to examples/apple_example/imguiex-ios/Shaders/Shader.vsh diff --git a/examples/ios_example/imguiex/debug_hud.cpp b/examples/apple_example/imguiex-ios/debug_hud.cpp similarity index 100% rename from examples/ios_example/imguiex/debug_hud.cpp rename to examples/apple_example/imguiex-ios/debug_hud.cpp diff --git a/examples/ios_example/imguiex/debug_hud.h b/examples/apple_example/imguiex-ios/debug_hud.h similarity index 100% rename from examples/ios_example/imguiex/debug_hud.h rename to examples/apple_example/imguiex-ios/debug_hud.h diff --git a/examples/ios_example/imguiex/imgui_ex_icon.png b/examples/apple_example/imguiex-ios/imgui_ex_icon.png similarity index 100% rename from examples/ios_example/imguiex/imgui_ex_icon.png rename to examples/apple_example/imguiex-ios/imgui_ex_icon.png diff --git a/examples/ios_example/imguiex/imgui_impl_ios.h b/examples/apple_example/imguiex-ios/imgui_impl_ios.h similarity index 100% rename from examples/ios_example/imguiex/imgui_impl_ios.h rename to examples/apple_example/imguiex-ios/imgui_impl_ios.h diff --git a/examples/ios_example/imguiex/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm similarity index 100% rename from examples/ios_example/imguiex/imgui_impl_ios.mm rename to examples/apple_example/imguiex-ios/imgui_impl_ios.mm diff --git a/examples/ios_example/imguiex/main.m b/examples/apple_example/imguiex-ios/main.m similarity index 100% rename from examples/ios_example/imguiex/main.m rename to examples/apple_example/imguiex-ios/main.m diff --git a/examples/apple_example/imguiex-osx/AppDelegate.h b/examples/apple_example/imguiex-osx/AppDelegate.h new file mode 100644 index 000000000..33d199bbf --- /dev/null +++ b/examples/apple_example/imguiex-osx/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// imguiex-osx +// +// Created by James Chen on 4/5/16. +// Copyright © 2016 Joel Davis. All rights reserved. +// + +#import + +@interface AppDelegate : NSObject + + +@end + diff --git a/examples/apple_example/imguiex-osx/AppDelegate.m b/examples/apple_example/imguiex-osx/AppDelegate.m new file mode 100644 index 000000000..59e877b39 --- /dev/null +++ b/examples/apple_example/imguiex-osx/AppDelegate.m @@ -0,0 +1,26 @@ +// +// AppDelegate.m +// imguiex-osx +// +// Created by James Chen on 4/5/16. +// Copyright © 2016 Joel Davis. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@property (weak) IBOutlet NSWindow *window; +@end + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Insert code here to initialize your application +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + // Insert code here to tear down your application +} + +@end diff --git a/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json b/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..b13908fc6 --- /dev/null +++ b/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,64 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "icon_imgui_180x180.png", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/icon_imgui_180x180.png b/examples/apple_example/imguiex-osx/Assets.xcassets/AppIcon.appiconset/icon_imgui_180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..f48b799dba2cf05b31924886eb4fc9d803ea4a83 GIT binary patch literal 5953 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 aW)oPOXB1N~w0~dYfLBm;#aac6u>S!7Vo}-v literal 0 HcmV?d00001 diff --git a/examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json b/examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json new file mode 100644 index 000000000..da4a164c9 --- /dev/null +++ b/examples/apple_example/imguiex-osx/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/apple_example/imguiex-osx/Info.plist b/examples/apple_example/imguiex-osx/Info.plist new file mode 100644 index 000000000..ba1c2bb00 --- /dev/null +++ b/examples/apple_example/imguiex-osx/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2016 Joel Davis. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/examples/apple_example/imguiex-osx/main.m b/examples/apple_example/imguiex-osx/main.m new file mode 100644 index 000000000..20b073137 --- /dev/null +++ b/examples/apple_example/imguiex-osx/main.m @@ -0,0 +1,13 @@ +// +// main.m +// imguiex-osx +// +// Created by James Chen on 4/5/16. +// Copyright © 2016 Joel Davis. All rights reserved. +// + +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} diff --git a/examples/ios_example/imguiex.xcodeproj/project.pbxproj b/examples/apple_example/imguiex.xcodeproj/project.pbxproj similarity index 66% rename from examples/ios_example/imguiex.xcodeproj/project.pbxproj rename to examples/apple_example/imguiex.xcodeproj/project.pbxproj index 26bcff493..652d15b6b 100644 --- a/examples/ios_example/imguiex.xcodeproj/project.pbxproj +++ b/examples/apple_example/imguiex.xcodeproj/project.pbxproj @@ -9,6 +9,16 @@ /* Begin PBXBuildFile section */ 197E1E871B8943FE00E3FE6A /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E861B8943FE00E3FE6A /* imgui_draw.cpp */; }; 197E1E891B89443600E3FE6A /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E881B89443600E3FE6A /* imgui_demo.cpp */; }; + 1A1A0F231CB39FB50090F036 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A0F221CB39FB50090F036 /* AppDelegate.m */; }; + 1A1A0F281CB39FB50090F036 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A1A0F271CB39FB50090F036 /* Assets.xcassets */; }; + 1A1A0F301CB3A0DA0090F036 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E861B8943FE00E3FE6A /* imgui_draw.cpp */; }; + 1A1A0F311CB3A0DA0090F036 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC5861B2E64AB00C130BA /* imgui.cpp */; }; + 1A1A0F321CB3A0DE0090F036 /* uSynergy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6D1E39151B35EEF10017B40F /* uSynergy.c */; }; + 1A1A0F331CB3A0E10090F036 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 197E1E881B89443600E3FE6A /* imgui_demo.cpp */; }; + 1A1A0F341CB3A0EC0090F036 /* debug_hud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC5891B2E6A5500C130BA /* debug_hud.cpp */; }; + 1A1A0F481CB3A2E50090F036 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A0F391CB3A1B20090F036 /* main.cpp */; }; + 1A1A0F4A1CB3A5070090F036 /* imgui_impl_glfw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */; }; + 1A1A0F4E1CB3C54D0090F036 /* libglfw3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */; }; 6D1E39171B35EEF10017B40F /* uSynergy.c in Sources */ = {isa = PBXBuildFile; fileRef = 6D1E39151B35EEF10017B40F /* uSynergy.c */; }; 6D2FC55A1B2E632000C130BA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC5591B2E632000C130BA /* main.m */; }; 6D2FC55D1B2E632000C130BA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D2FC55C1B2E632000C130BA /* AppDelegate.m */; }; @@ -28,9 +38,18 @@ /* Begin PBXFileReference section */ 197E1E861B8943FE00E3FE6A /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = ../../imgui_draw.cpp; sourceTree = ""; }; 197E1E881B89443600E3FE6A /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../../imgui_demo.cpp; sourceTree = ""; }; + 1A1A0F1F1CB39FB50090F036 /* imguiex-osx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "imguiex-osx.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1A1A0F211CB39FB50090F036 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 1A1A0F221CB39FB50090F036 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 1A1A0F271CB39FB50090F036 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1A1A0F2C1CB39FB50090F036 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = imgui_impl_glfw.cpp; sourceTree = ""; }; + 1A1A0F381CB3A1B20090F036 /* imgui_impl_glfw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imgui_impl_glfw.h; sourceTree = ""; }; + 1A1A0F391CB3A1B20090F036 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libglfw3.dylib; path = /usr/local/lib/libglfw3.dylib; sourceTree = ""; }; 6D1E39151B35EEF10017B40F /* uSynergy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uSynergy.c; sourceTree = ""; }; 6D1E39161B35EEF10017B40F /* uSynergy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uSynergy.h; sourceTree = ""; }; - 6D2FC5541B2E632000C130BA /* imguiex.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = imguiex.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 6D2FC5541B2E632000C130BA /* imguiex-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "imguiex-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 6D2FC5581B2E632000C130BA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6D2FC5591B2E632000C130BA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 6D2FC55B1B2E632000C130BA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -54,6 +73,14 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 1A1A0F1C1CB39FB50090F036 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A1A0F4E1CB3C54D0090F036 /* libglfw3.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6D2FC5511B2E632000C130BA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -66,6 +93,38 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1A1A0F201CB39FB50090F036 /* imguiex-osx */ = { + isa = PBXGroup; + children = ( + 1A1A0F4D1CB3C54D0090F036 /* libglfw3.dylib */, + 1A1A0F351CB3A1B20090F036 /* opengl_example */, + 1A1A0F211CB39FB50090F036 /* AppDelegate.h */, + 1A1A0F221CB39FB50090F036 /* AppDelegate.m */, + 1A1A0F271CB39FB50090F036 /* Assets.xcassets */, + 1A1A0F2C1CB39FB50090F036 /* Info.plist */, + 1A1A0F241CB39FB50090F036 /* Supporting Files */, + ); + path = "imguiex-osx"; + sourceTree = ""; + }; + 1A1A0F241CB39FB50090F036 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 1A1A0F351CB3A1B20090F036 /* opengl_example */ = { + isa = PBXGroup; + children = ( + 1A1A0F371CB3A1B20090F036 /* imgui_impl_glfw.cpp */, + 1A1A0F381CB3A1B20090F036 /* imgui_impl_glfw.h */, + 1A1A0F391CB3A1B20090F036 /* main.cpp */, + ); + name = opengl_example; + path = ../../opengl_example; + sourceTree = ""; + }; 6D1E39141B35EEF10017B40F /* usynergy */ = { isa = PBXGroup; children = ( @@ -81,7 +140,8 @@ children = ( 6D1E39141B35EEF10017B40F /* usynergy */, 6D2FC5841B2E648D00C130BA /* imgui */, - 6D2FC5561B2E632000C130BA /* imguiex */, + 6D2FC5561B2E632000C130BA /* imguiex-ios */, + 1A1A0F201CB39FB50090F036 /* imguiex-osx */, 6D2FC5551B2E632000C130BA /* Products */, ); sourceTree = ""; @@ -89,12 +149,13 @@ 6D2FC5551B2E632000C130BA /* Products */ = { isa = PBXGroup; children = ( - 6D2FC5541B2E632000C130BA /* imguiex.app */, + 6D2FC5541B2E632000C130BA /* imguiex-ios.app */, + 1A1A0F1F1CB39FB50090F036 /* imguiex-osx.app */, ); name = Products; sourceTree = ""; }; - 6D2FC5561B2E632000C130BA /* imguiex */ = { + 6D2FC5561B2E632000C130BA /* imguiex-ios */ = { isa = PBXGroup; children = ( 6D2FC5811B2E63A100C130BA /* imgui_impl_ios.mm */, @@ -113,7 +174,7 @@ 6D2FC56A1B2E632000C130BA /* LaunchScreen.xib */, 6D2FC5571B2E632000C130BA /* Supporting Files */, ); - path = imguiex; + path = "imguiex-ios"; sourceTree = ""; }; 6D2FC5571B2E632000C130BA /* Supporting Files */ = { @@ -141,9 +202,26 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 6D2FC5531B2E632000C130BA /* imguiex */ = { + 1A1A0F1E1CB39FB50090F036 /* imguiex-osx */ = { isa = PBXNativeTarget; - buildConfigurationList = 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex" */; + buildConfigurationList = 1A1A0F2F1CB39FB50090F036 /* Build configuration list for PBXNativeTarget "imguiex-osx" */; + buildPhases = ( + 1A1A0F1B1CB39FB50090F036 /* Sources */, + 1A1A0F1C1CB39FB50090F036 /* Frameworks */, + 1A1A0F1D1CB39FB50090F036 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "imguiex-osx"; + productName = "imguiex-osx"; + productReference = 1A1A0F1F1CB39FB50090F036 /* imguiex-osx.app */; + productType = "com.apple.product-type.application"; + }; + 6D2FC5531B2E632000C130BA /* imguiex-ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex-ios" */; buildPhases = ( 6D2FC5501B2E632000C130BA /* Sources */, 6D2FC5511B2E632000C130BA /* Frameworks */, @@ -153,9 +231,9 @@ ); dependencies = ( ); - name = imguiex; + name = "imguiex-ios"; productName = imguiex; - productReference = 6D2FC5541B2E632000C130BA /* imguiex.app */; + productReference = 6D2FC5541B2E632000C130BA /* imguiex-ios.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -167,6 +245,9 @@ LastUpgradeCheck = 0630; ORGANIZATIONNAME = "Joel Davis"; TargetAttributes = { + 1A1A0F1E1CB39FB50090F036 = { + CreatedOnToolsVersion = 7.3; + }; 6D2FC5531B2E632000C130BA = { CreatedOnToolsVersion = 6.3.2; }; @@ -185,12 +266,21 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 6D2FC5531B2E632000C130BA /* imguiex */, + 6D2FC5531B2E632000C130BA /* imguiex-ios */, + 1A1A0F1E1CB39FB50090F036 /* imguiex-osx */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 1A1A0F1D1CB39FB50090F036 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A1A0F281CB39FB50090F036 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6D2FC5521B2E632000C130BA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -206,6 +296,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 1A1A0F1B1CB39FB50090F036 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A1A0F301CB3A0DA0090F036 /* imgui_draw.cpp in Sources */, + 1A1A0F311CB3A0DA0090F036 /* imgui.cpp in Sources */, + 1A1A0F331CB3A0E10090F036 /* imgui_demo.cpp in Sources */, + 1A1A0F341CB3A0EC0090F036 /* debug_hud.cpp in Sources */, + 1A1A0F481CB3A2E50090F036 /* main.cpp in Sources */, + 1A1A0F321CB3A0DE0090F036 /* uSynergy.c in Sources */, + 1A1A0F231CB39FB50090F036 /* AppDelegate.m in Sources */, + 1A1A0F4A1CB3A5070090F036 /* imgui_impl_glfw.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 6D2FC5501B2E632000C130BA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -244,6 +349,54 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 1A1A0F2D1CB39FB50090F036 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../", + /usr/local/include, + ); + INFOPLIST_FILE = "imguiex-osx/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.imguiex.imguiex-osx"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Debug; + }; + 1A1A0F2E1CB39FB50090F036 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../", + /usr/local/include, + ); + INFOPLIST_FILE = "imguiex-osx/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = /usr/local/lib; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.imguiex.imguiex-osx"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + USER_HEADER_SEARCH_PATHS = ""; + }; + name = Release; + }; 6D2FC5791B2E632000C130BA /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -280,11 +433,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ""; }; name = Debug; }; @@ -318,10 +473,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/../../"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ""; VALIDATE_PRODUCT = YES; }; name = Release; @@ -330,7 +487,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = imguiex/Info.plist; + INFOPLIST_FILE = "imguiex-ios/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -340,7 +497,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = imguiex/Info.plist; + INFOPLIST_FILE = "imguiex-ios/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -349,6 +506,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 1A1A0F2F1CB39FB50090F036 /* Build configuration list for PBXNativeTarget "imguiex-osx" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1A1A0F2D1CB39FB50090F036 /* Debug */, + 1A1A0F2E1CB39FB50090F036 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 6D2FC54F1B2E632000C130BA /* Build configuration list for PBXProject "imguiex" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -358,7 +524,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex" */ = { + 6D2FC57B1B2E632000C130BA /* Build configuration list for PBXNativeTarget "imguiex-ios" */ = { isa = XCConfigurationList; buildConfigurations = ( 6D2FC57C1B2E632000C130BA /* Debug */, From 71b981d05fbf077c0d5b9cfeffa7a3de979810c7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 5 Apr 2016 22:50:23 +0200 Subject: [PATCH 19/24] Examples: Apple: Readme tweaks (#575 #247) --- examples/README.txt | 6 +++--- examples/apple_example/README.md | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/README.txt b/examples/README.txt index 0259ae64a..df6fe879c 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -63,9 +63,9 @@ directx11_example/ DirectX11 example, Windows only. This is quite long and tedious, because: DirectX11. -ios_example/ - iOS example. - Using Synergy to access keyboard/mouse data from server computer. +apple_example/ + OSX & iOS example. + On iOS, Using Synergy to access keyboard/mouse data from server computer. Synergy keyboard integration is rather hacky. sdl_opengl_example/ diff --git a/examples/apple_example/README.md b/examples/apple_example/README.md index c847f1a3e..1d2355e06 100644 --- a/examples/apple_example/README.md +++ b/examples/apple_example/README.md @@ -2,19 +2,19 @@ ## Introduction -This example is the default XCode "OpenGL" example code, modified to support ImGui and [Synergy](http://synergy-project.org/). +This example is the default XCode "OpenGL" example code, modified to support ImGui (and [Synergy](http://synergy-project.org/) to share mouse/keyboard with an iOS device). It is a rather complex example because of all of the faff required to get an XCode/iOS application running. Refer to the regular OpenGL examples if you want to learn about integrating ImGui. Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImGui without it. Synergy includes a "uSynergy" library that allows embedding a synergy client, this is what is used here. ImGui supports "TouchPadding", and this is enabled when Synergy is not active. -## How to Use +## How to Use on iOS -0. In Synergy, go to Preferences, and uncheck "Use SSL encryption" -0. Run the example app. -0. Tap the "servername" button in the corner -0. Enter the name or the IP of your synergy host -0. If you had previously connected to a server, you may need to kill and re-start the app. +* In Synergy, go to Preferences, and uncheck "Use SSL encryption" +* Run the example app. +* Tap the "servername" button in the corner +* Enter the name or the IP of your synergy host +* If you had previously connected to a server, you may need to kill and re-start the app. ## How to Run on OSX @@ -33,6 +33,7 @@ Things that would be nice but I didn't get around to doing: * Copy/Paste not well-supported ## C++ on iOS / OSX + ImGui is a c++ library. If you want to include it directly, rename your Obj-C file to have the ".mm" extension. Alternatively, you can wrap your debug code in a C interface, this is what I am demonstrating here with the "debug_hud.h" interface. Either approach works, use whatever you prefer. From 319e288eef920d39916dd6e250eec31047f91a5b Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 5 Apr 2016 23:08:21 +0200 Subject: [PATCH 20/24] Update README.md --- examples/apple_example/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/apple_example/README.md b/examples/apple_example/README.md index 1d2355e06..339f6bf85 100644 --- a/examples/apple_example/README.md +++ b/examples/apple_example/README.md @@ -2,9 +2,9 @@ ## Introduction -This example is the default XCode "OpenGL" example code, modified to support ImGui (and [Synergy](http://synergy-project.org/) to share mouse/keyboard with an iOS device). +This example is the default XCode "OpenGL" example code, modified to support ImGui and [Synergy](http://synergy-project.org/) to share mouse/keyboard on an iOS device. -It is a rather complex example because of all of the faff required to get an XCode/iOS application running. Refer to the regular OpenGL examples if you want to learn about integrating ImGui. +It is a rather complex and messy example because of all of the faff required to get an XCode/iOS application running. Refer to the regular OpenGL examples if you want to learn about integrating ImGui. **The opengl3_example/ should also work on OS X and is much simpler.** This is an integration for iOS with Synergy. Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImGui without it. Synergy includes a "uSynergy" library that allows embedding a synergy client, this is what is used here. ImGui supports "TouchPadding", and this is enabled when Synergy is not active. @@ -16,7 +16,7 @@ Synergy (remote keyboard/mouse) is not required, but it's pretty hard to use ImG * Enter the name or the IP of your synergy host * If you had previously connected to a server, you may need to kill and re-start the app. -## How to Run on OSX +## How to Build on OSX * Make sure you have install `brew`, if not, please refer to [Homebrew Website](http://brew.sh) * Run the command: `brew install glfw3` From 31852e1d05007f6a880d5249445af6bde3752485 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Apr 2016 11:11:30 +0200 Subject: [PATCH 21/24] Silence borderline warning with -Werror=strict-overflow Error: assuming signed overflow does not occur when assuming that (X - c) > X is always false [-Werror=strict-overflow] --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index eb809f2af..9410376f0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1652,7 +1652,7 @@ ImGuiWindow* ImGui::GetParentWindow() { ImGuiState& g = *GImGui; IM_ASSERT(g.CurrentWindowStack.Size >= 2); - return g.CurrentWindowStack[g.CurrentWindowStack.Size - 2]; + return g.CurrentWindowStack[(unsigned int)g.CurrentWindowStack.Size - 2]; } void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL) From 4c25de950cfb1ef55aa2643b116a752aeba830b8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 9 Apr 2016 17:46:38 +0200 Subject: [PATCH 22/24] Warning fixes for clang. Using int64_t, may be an issue? --- imgui.cpp | 8 ++++---- imgui.h | 5 +++-- imgui_demo.cpp | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9410376f0..efee251a7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2339,9 +2339,9 @@ static void AddDrawListToRenderList(ImVector& out_render_list, ImDr // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = 2 bytes = 64K vertices) // If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly. - IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Sanity check. Bug or mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. - IM_ASSERT((unsigned long long int)draw_list->_VtxCurrentIdx <= ((unsigned long long int)1L << (sizeof(ImDrawIdx)*8))); // Too many vertices in same ImDrawList. See comment above. - + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); // Sanity check. Bug or mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + IM_ASSERT((int64_t)draw_list->_VtxCurrentIdx <= ((int64_t)1L << (sizeof(ImDrawIdx)*8))); // Too many vertices in same ImDrawList. See comment above. + out_render_list.push_back(draw_list); GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size; GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size; @@ -7098,9 +7098,9 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; } -static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; } static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } #ifdef __APPLE__ // FIXME: Move setting to IO structure +static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; } static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } #else static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } diff --git a/imgui.h b/imgui.h index c4834e79a..660d3f089 100644 --- a/imgui.h +++ b/imgui.h @@ -315,7 +315,7 @@ namespace ImGui IMGUI_API void TreePush(const char* str_id = NULL); // already called by TreeNode(), but you can call Push/Pop yourself for layouting purpose IMGUI_API void TreePush(const void* ptr_id = NULL); // " IMGUI_API void TreePop(); - IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened. + IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node/collapsing header to be opened. // Widgets: Selectable / Lists IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0,0)); // size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height @@ -890,6 +890,7 @@ struct ImGuiTextFilter int CountGrep; ImGuiTextFilter(const char* default_filter = ""); + ~ImGuiTextFilter() {} void Clear() { InputBuf[0] = 0; Build(); } bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build bool PassFilter(const char* text, const char* text_end = NULL) const; @@ -1152,7 +1153,7 @@ struct ImDrawList // Stateful path API, add points then finish with PathFill() or PathStroke() inline void PathClear() { _Path.resize(0); } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } - inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || _Path[_Path.Size-1].x != pos.x || _Path[_Path.Size-1].y != pos.y) _Path.push_back(pos); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } inline void PathFill(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col, true); PathClear(); } inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness, true); PathClear(); } IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a7268d480..83f380085 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2295,12 +2295,12 @@ static void ShowExampleAppPropertyEditor(bool* opened) { ImGui::PushID(uid); // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID. ImGui::AlignFirstTextHeightToWidgets(); // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high. - bool opened = ImGui::TreeNode("Object", "%s_%u", prefix, uid); + bool is_opened = ImGui::TreeNode("Object", "%s_%u", prefix, uid); ImGui::NextColumn(); ImGui::AlignFirstTextHeightToWidgets(); ImGui::Text("my sailor is rich"); ImGui::NextColumn(); - if (opened) + if (is_opened) { static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f }; for (int i = 0; i < 8; i++) From 95cbcdca3fcf84bf94b3bb4374d884b1d4bc5db0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 9 Apr 2016 17:46:48 +0200 Subject: [PATCH 23/24] Version 1.48 --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index efee251a7..191cc0594 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (main code and documentation) // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index 660d3f089..c353e97e1 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (headers) // See imgui.cpp file for documentation. @@ -16,7 +16,7 @@ #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.48 WIP" +#define IMGUI_VERSION "1.48" // Define attributes of all API symbols declarations, e.g. for DLL under Windows. #ifndef IMGUI_API diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 83f380085..d469473aa 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (demo code) // Don't remove this file from your project! It is useful reference code that you can execute. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 95871b60b..533ecdaec 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (drawing and font code) // Contains implementation for diff --git a/imgui_internal.h b/imgui_internal.h index 0f654a541..3dd17e64b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 WIP +// dear imgui, v1.48 // (internals) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! From 1588eda1ac70f8ea88a1b639858b31b59bdb93ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 9 Apr 2016 19:10:42 +0200 Subject: [PATCH 24/24] Version 1.49 WIP --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 191cc0594..1cca7e925 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (main code and documentation) // See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code. diff --git a/imgui.h b/imgui.h index c353e97e1..ac21c4ab8 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (headers) // See imgui.cpp file for documentation. @@ -16,7 +16,7 @@ #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.48" +#define IMGUI_VERSION "1.49 WIP" // Define attributes of all API symbols declarations, e.g. for DLL under Windows. #ifndef IMGUI_API diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d469473aa..146df3003 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (demo code) // Don't remove this file from your project! It is useful reference code that you can execute. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 533ecdaec..1d268561b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (drawing and font code) // Contains implementation for diff --git a/imgui_internal.h b/imgui_internal.h index 3dd17e64b..e886ff1bb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.48 +// dear imgui, v1.49 WIP // (internals) // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!