diff --git a/src/hello_imgui/image_from_asset.h b/src/hello_imgui/image_from_asset.h index 17e05e8a..eaf4b648 100644 --- a/src/hello_imgui/image_from_asset.h +++ b/src/hello_imgui/image_from_asset.h @@ -34,6 +34,9 @@ namespace HelloImGui void ImageFromAsset(const char *assetPath, const ImVec2& size = ImVec2(0, 0), const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); bool ImageButtonFromAsset(const char *assetPath, const ImVec2& size = ImVec2(0, 0), const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); ImTextureID ImTextureIdFromAsset(const char *assetPath); + ImVec2 ImageSizeFromAsset(const char *assetPath); + + ImVec2 ImageProportionalSize(const ImVec2& askedSize, const ImVec2& imageSize); namespace internal { diff --git a/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp b/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp index 7b99b929..cc41426f 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp +++ b/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp @@ -81,10 +81,6 @@ namespace HelloImGui VkResult err = vkDeviceWaitIdle(gVkGlobals.Device); HelloImGui::VulkanSetup::check_vk_result(err); ImGui_ImplVulkan_Shutdown(); - - //ImGui_ImplGlfw_Shutdown(); - // ImGui::DestroyContext(); - HelloImGui::VulkanSetup::CleanupVulkanWindow(); HelloImGui::VulkanSetup::CleanupVulkan(); }; diff --git a/src/hello_imgui/internal/image_from_asset.cpp b/src/hello_imgui/internal/image_from_asset.cpp index 3ae66135..fda2a8bc 100644 --- a/src/hello_imgui/internal/image_from_asset.cpp +++ b/src/hello_imgui/internal/image_from_asset.cpp @@ -1,86 +1,17 @@ -#ifdef HELLOIMGUI_HAS_OPENGL -#include "hello_imgui/image_gl.h" - -#include -#include +#include "image_from_asset.h" namespace HelloImGui { -std::unordered_map gImageFromAssetMap; - -void _LoadImageGl(const char *assetPath) -{ - if (gImageFromAssetMap.find(assetPath) == gImageFromAssetMap.end()) - gImageFromAssetMap[assetPath] = ImageGl::FactorImage(assetPath); -} - -void ImageFromAsset(const char *assetPath, const ImVec2 &size, const ImVec2 &uv0, const ImVec2 &uv1, - const ImVec4 &tint_col, const ImVec4 &border_col) -{ - _LoadImageGl(assetPath); - gImageFromAssetMap.at(assetPath)->Draw(size, uv0, uv1, tint_col, border_col); -} - -bool ImageButtonFromAsset(const char *assetPath, const ImVec2 &size, const ImVec2 &uv0, const ImVec2 &uv1, - int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col) -{ - _LoadImageGl(assetPath); - return gImageFromAssetMap.at(assetPath)->DrawButton(size, uv0, uv1, frame_padding, bg_col, tint_col); -} - -ImTextureID ImTextureIdFromAsset(const char *assetPath) -{ - _LoadImageGl(assetPath); - return gImageFromAssetMap.at(assetPath)->imTextureId; -} - - -namespace internal -{ - void Free_ImageFromAssetMap() + ImVec2 ImageProportionalSize(const ImVec2& askedSize, const ImVec2& imageSize) { - // this function is called by HelloImGui during the application's TearDown - // and will clear all asset images textures when the OpenGL context is still valid. - gImageFromAssetMap.clear(); + ImVec2 r(askedSize); + + if ((r.x == 0.f) && (r.y == 0.f)) + r = imageSize; + else if (r.y == 0.f) + r.y = imageSize.y / imageSize.x * r.x; + else if (r.x == 0.f) + r.x = imageSize.x / imageSize.y * r.y; + return r; } } - -} // namespace HelloImGui - - -#elif defined(HELLOIMGUI_HAS_VULKAN) -// See image_from_asset_vulkan.cpp - -#else // #ifdef HELLOIMGUI_HAS_OPENGL - -#include "imgui.h" - -namespace HelloImGui -{ -void ImageFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) -{ - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); - ImGui::Text("ImageFromAsset requires OpenGL"); - ImGui::PopStyleColor(); -} - -bool ImageButtonFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) -{ - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); - ImGui::Text("ButtonFromAsset requires OpenGL"); - ImGui::PopStyleColor(); - return false; -} - -ImTextureID ImTextureIDFromAsset(const char *assetPath) -{ - // Requires OpenGL! - return nullptr; -} - -namespace internal -{ - void Free_ImageFromAssetMap() {} -} -} // namespace HelloImGui -#endif // #ifdef HELLOIMGUI_HAS_OPENGL diff --git a/src/hello_imgui/internal/image_from_asset_none.cpp b/src/hello_imgui/internal/image_from_asset_none.cpp new file mode 100644 index 00000000..df03964a --- /dev/null +++ b/src/hello_imgui/internal/image_from_asset_none.cpp @@ -0,0 +1,41 @@ +#include "image_from_asset.h" + + +#if !defined(HELLOIMGUI_HAS_VULKAN) && !defined(HELLOIMGUI_HAS_OPENGL) + +#include "imgui.h" + +namespace HelloImGui +{ + void ImageFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); + ImGui::Text("ImageFromAsset not available"); + ImGui::PopStyleColor(); + } + + bool ImageButtonFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); + ImGui::Text("ButtonFromAsset not available"); + ImGui::PopStyleColor(); + return false; + } + + ImTextureID ImTextureIDFromAsset(const char *assetPath) + { + // Requires OpenGL! + return nullptr; + } + + ImVec2 ImageSizeFromAsset(const char *assetPath) + { + return ImVec2(0.f, 0.f); + } + + namespace internal + { + void Free_ImageFromAssetMap() {} + } +} // namespace HelloImGui +#endif // #if !defined(HELLOIMGUI_HAS_VULKAN) && !defined(HELLOIMGUI_HAS_OPENGL) diff --git a/src/hello_imgui/internal/image_from_asset_opengl.cpp b/src/hello_imgui/internal/image_from_asset_opengl.cpp new file mode 100644 index 00000000..10c2fc4f --- /dev/null +++ b/src/hello_imgui/internal/image_from_asset_opengl.cpp @@ -0,0 +1,59 @@ +#include "image_from_asset.h" + +#ifdef HELLOIMGUI_HAS_OPENGL +#include "hello_imgui/image_gl.h" + +#include +#include + +namespace HelloImGui +{ + static std::unordered_map gImageFromAssetMap; + + void _LoadImageGl(const char *assetPath) + { + if (gImageFromAssetMap.find(assetPath) == gImageFromAssetMap.end()) + gImageFromAssetMap[assetPath] = ImageGl::FactorImage(assetPath); + } + + void ImageFromAsset(const char *assetPath, const ImVec2 &size, const ImVec2 &uv0, const ImVec2 &uv1, + const ImVec4 &tint_col, const ImVec4 &border_col) + { + _LoadImageGl(assetPath); + gImageFromAssetMap.at(assetPath)->Draw(size, uv0, uv1, tint_col, border_col); + } + + bool ImageButtonFromAsset(const char *assetPath, const ImVec2 &size, const ImVec2 &uv0, const ImVec2 &uv1, + int frame_padding, const ImVec4 &bg_col, const ImVec4 &tint_col) + { + _LoadImageGl(assetPath); + return gImageFromAssetMap.at(assetPath)->DrawButton(size, uv0, uv1, frame_padding, bg_col, tint_col); + } + + ImTextureID ImTextureIdFromAsset(const char *assetPath) + { + _LoadImageGl(assetPath); + return gImageFromAssetMap.at(assetPath)->imTextureId; + } + + ImVec2 ImageSizeFromAsset(const char *assetPath) + { + _LoadImageGl(assetPath); + return gImageFromAssetMap.at(assetPath)->imageSize; + } + + + namespace internal + { + void Free_ImageFromAssetMap() + { + // this function is called by HelloImGui during the application's TearDown + // and will clear all asset images textures when the OpenGL context is still valid. + gImageFromAssetMap.clear(); + } + } + +} // namespace HelloImGui + + +#endif // #ifdef HELLOIMGUI_HAS_OPENGL diff --git a/src/hello_imgui/internal/image_from_asset_vulkan.cpp b/src/hello_imgui/internal/image_from_asset_vulkan.cpp index eb14e152..352870ba 100644 --- a/src/hello_imgui/internal/image_from_asset_vulkan.cpp +++ b/src/hello_imgui/internal/image_from_asset_vulkan.cpp @@ -1,14 +1,45 @@ #ifdef HELLOIMGUI_HAS_VULKAN #include "hello_imgui/image_from_asset.h" #include "imgui.h" -#include "hello_imgui/internal/backend_impls/image_vulkan.h" +#include "hello_imgui/internal/image_vulkan.h" +#include "hello_imgui/internal/stb_image.h" +#include "hello_imgui/hello_imgui_assets.h" #include #include namespace HelloImGui { - std::unordered_map gImageFromAssetMap; + static std::unordered_map gImageFromAssetMap; + + + static ImageVkPtr _GetCachedImageVk(const char*assetPath) + { + if (gImageFromAssetMap.find(assetPath) != gImageFromAssetMap.end()) + return gImageFromAssetMap.at(assetPath); + + // Load the image using stbi_load_from_memory + auto assetData = LoadAssetFileData(assetPath); + assert(assetData.data != nullptr); + int width, height; + unsigned char*image_data_rgba = stbi_load_from_memory( + (unsigned char *)assetData.data, (int)assetData.dataSize, + &width, &height, NULL, 4); + if (image_data_rgba == NULL) + { + IM_ASSERT(false && "ImageVk: Failed to load image!"); + return nullptr; + } + + // Create and store the VkImage + if (gImageFromAssetMap.find(assetPath) == gImageFromAssetMap.end()) + gImageFromAssetMap[assetPath] = std::make_shared(width, height, image_data_rgba); + + // Release image memory using stb + stbi_image_free(image_data_rgba); + + return gImageFromAssetMap.at(assetPath); + } void ImageFromAsset( const char *assetPath, const ImVec2& size, @@ -16,23 +47,30 @@ namespace HelloImGui const ImVec4& tint_col, const ImVec4& border_col) { auto textureId = ImTextureIdFromAsset(assetPath); - - ImGui::Image(textureId, size, uv0, uv1, tint_col, border_col); + auto imageSize = ImageSizeFromAsset(assetPath); + ImVec2 displayedSize = ImageProportionalSize(size, imageSize); + ImGui::Image(textureId, displayedSize, uv0, uv1, tint_col, border_col); } bool ImageButtonFromAsset(const char *assetPath, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { auto textureId = ImTextureIdFromAsset(assetPath); - bool clicked = ImGui::ImageButton(textureId, size, uv0, uv1, frame_padding, bg_col, tint_col); + auto imageSize = ImageSizeFromAsset(assetPath); + ImVec2 displayedSize = ImageProportionalSize(size, imageSize); + bool clicked = ImGui::ImageButton(textureId, displayedSize, uv0, uv1, frame_padding, bg_col, tint_col); return clicked; } ImTextureID ImTextureIdFromAsset(const char *assetPath) { - if (gImageFromAssetMap.find(assetPath) == gImageFromAssetMap.end()) - gImageFromAssetMap[assetPath] = std::make_shared(assetPath); + auto cachedImage = _GetCachedImageVk(assetPath); + return (ImTextureID) cachedImage->DS; + } - return (ImTextureID) gImageFromAssetMap.at(assetPath)->DS; + ImVec2 ImageSizeFromAsset(const char *assetPath) + { + auto cachedImage = _GetCachedImageVk(assetPath); + return ImVec2((float)cachedImage->Width, (float)cachedImage->Height); } namespace internal diff --git a/src/hello_imgui/internal/image_gl.cpp b/src/hello_imgui/internal/image_gl.cpp index c145ec5c..0f3c2497 100644 --- a/src/hello_imgui/internal/image_gl.cpp +++ b/src/hello_imgui/internal/image_gl.cpp @@ -44,18 +44,7 @@ ImageGl::~ImageGl() } -ImVec2 ImageProportionalSize(const ImVec2& askedSize, const ImVec2& imageSize) -{ - ImVec2 r(askedSize); - - if ((r.x == 0.f) && (r.y == 0.f)) - r = imageSize; - else if (r.y == 0.f) - r.y = imageSize.y / imageSize.x * r.x; - else if (r.x == 0.f) - r.x = imageSize.x / imageSize.y * r.y; - return r; -} +ImVec2 ImageProportionalSize(const ImVec2& askedSize, const ImVec2& imageSize); void ImageGl::Draw( diff --git a/src/hello_imgui/internal/backend_impls/image_vulkan.cpp b/src/hello_imgui/internal/image_vulkan.cpp similarity index 93% rename from src/hello_imgui/internal/backend_impls/image_vulkan.cpp rename to src/hello_imgui/internal/image_vulkan.cpp index 34255d1c..065c9d43 100644 --- a/src/hello_imgui/internal/backend_impls/image_vulkan.cpp +++ b/src/hello_imgui/internal/image_vulkan.cpp @@ -3,8 +3,6 @@ #include "imgui.h" #include "hello_imgui/internal/backend_impls/rendering_vulkan.h" -#include "hello_imgui/internal/stb_image.h" -#include "hello_imgui/hello_imgui_assets.h" // Inspired from https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples#example-for-vulkan-users // WARNING: THIS IS ONE WAY TO DO THIS AMONG MANY, and provided for informational purpose. @@ -29,25 +27,14 @@ namespace HelloImGui return 0xFFFFFFFF; // Unable to find memoryType } - ImageVk::ImageVk(const char *assetPath) + ImageVk::ImageVk(int width, int height, unsigned char* image_data_rgba) { VulkanGlobals& vkGlobals = GetVulkanGlobals(); auto &self = *this; - // Load the image using stbi_load_from_memory - // ... - auto assetData = LoadAssetFileData(assetPath); - assert(assetData.data != nullptr); - - unsigned char*image_data = stbi_load_from_memory( - (unsigned char *)assetData.data, (int)assetData.dataSize, - &self.Width, &self.Height, NULL, 4); - - if (image_data == NULL) { - IM_ASSERT(false && "ImageVk: Failed to load image!"); - return; - } + self.Width = width; + self.Height = height; // Calculate allocation size (in number of bytes) @@ -145,7 +132,7 @@ namespace HelloImGui void* map = NULL; err = vkMapMemory(vkGlobals.Device, self.UploadBufferMemory, 0, image_size, 0, &map); VulkanSetup::check_vk_result(err); - memcpy(map, image_data, image_size); + memcpy(map, image_data_rgba, image_size); VkMappedMemoryRange range[1] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[0].memory = self.UploadBufferMemory; @@ -155,9 +142,6 @@ namespace HelloImGui vkUnmapMemory(vkGlobals.Device, self.UploadBufferMemory); } - // Release image memory using stb - stbi_image_free(image_data); - // Create a command buffer that will perform following steps when hit in the command queue. // TODO: this works in the example, but may need input if this is an acceptable way to access the pool/create the command buffer. VkCommandPool command_pool = vkGlobals.ImGuiMainWindowData.Frames[vkGlobals.ImGuiMainWindowData.FrameIndex].CommandPool; diff --git a/src/hello_imgui/internal/backend_impls/image_vulkan.h b/src/hello_imgui/internal/image_vulkan.h similarity index 82% rename from src/hello_imgui/internal/backend_impls/image_vulkan.h rename to src/hello_imgui/internal/image_vulkan.h index e5377ddd..15738aab 100644 --- a/src/hello_imgui/internal/backend_impls/image_vulkan.h +++ b/src/hello_imgui/internal/image_vulkan.h @@ -8,13 +8,13 @@ namespace HelloImGui { struct ImageVk { - ImageVk(const char *assetPath); + ImageVk(int width, int height, unsigned char* image_data_rgba); ~ImageVk(); VkDescriptorSet DS; // Descriptor set: this is what you'll pass to Image() int Width = 0; int Height = 0; - int Channels = 4; + static constexpr int Channels = 4; // We intentionally only support RGBA for now // Need to keep track of these to properly cleanup VkImageView ImageView = nullptr;