Skip to content

Commit

Permalink
Work on image_from_asset (refactor)
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Dec 30, 2023
1 parent abba97c commit 9496f47
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 125 deletions.
3 changes: 3 additions & 0 deletions src/hello_imgui/image_from_asset.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
24 changes: 4 additions & 20 deletions src/hello_imgui/internal/backend_impls/image_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/hello_imgui/internal/backend_impls/image_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 0 additions & 4 deletions src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};
Expand Down
91 changes: 11 additions & 80 deletions src/hello_imgui/internal/image_from_asset.cpp
Original file line number Diff line number Diff line change
@@ -1,86 +1,17 @@
#ifdef HELLOIMGUI_HAS_OPENGL
#include "hello_imgui/image_gl.h"

#include <string>
#include <unordered_map>
#include "image_from_asset.h"

namespace HelloImGui
{
std::unordered_map<std::string, ImageGlPtr> 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
41 changes: 41 additions & 0 deletions src/hello_imgui/internal/image_from_asset_none.cpp
Original file line number Diff line number Diff line change
@@ -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)
59 changes: 59 additions & 0 deletions src/hello_imgui/internal/image_from_asset_opengl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "image_from_asset.h"

#ifdef HELLOIMGUI_HAS_OPENGL
#include "hello_imgui/image_gl.h"

#include <string>
#include <unordered_map>

namespace HelloImGui
{
static std::unordered_map<std::string, ImageGlPtr> 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
52 changes: 45 additions & 7 deletions src/hello_imgui/internal/image_from_asset_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,75 @@
#include "hello_imgui/image_from_asset.h"
#include "imgui.h"
#include "hello_imgui/internal/backend_impls/image_vulkan.h"
#include "hello_imgui/internal/stb_image.h"
#include "hello_imgui/hello_imgui_assets.h"

#include <string>
#include <unordered_map>

namespace HelloImGui
{
std::unordered_map<std::string, ImageVkPtr> gImageFromAssetMap;
static std::unordered_map<std::string, ImageVkPtr> 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<ImageVk>(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,
const ImVec2& uv0, const ImVec2& uv1,
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<ImageVk>(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
Expand Down
13 changes: 1 addition & 12 deletions src/hello_imgui/internal/image_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 9496f47

Please sign in to comment.