Skip to content

Commit 1df0eea

Browse files
committed
impr: Added support for SVG loading, improved texture loading API
1 parent ef99e9d commit 1df0eea

File tree

26 files changed

+878
-81
lines changed

26 files changed

+878
-81
lines changed

.gitmodules

+10-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@
2222
path = lib/third_party/jthread/jthread
2323
url = https://github.com/josuttis/jthread
2424
ignore = dirty
25+
url = https://github.com/WerWolv/HashLibPlus
26+
[submodule "lib/third_party/edlib"]
27+
path = lib/third_party/edlib
28+
url = https://github.com/Martinsos/edlib
29+
ignore = dirty
30+
[submodule "lib/third_party/lunasvg"]
31+
path = lib/third_party/lunasvg
32+
url = https://github.com/sammycage/lunasvg
33+
ignore = dirty
2534

2635
[submodule "lib/external/libromfs"]
2736
path = lib/external/libromfs
@@ -34,8 +43,4 @@
3443
url = https://github.com/WerWolv/libwolv
3544

3645
[submodule "lib/third_party/HashLibPlus"]
37-
path = lib/third_party/HashLibPlus
38-
url = https://github.com/WerWolv/HashLibPlus
39-
[submodule "lib/third_party/edlib"]
40-
path = lib/third_party/edlib
41-
url = https://github.com/Martinsos/edlib
46+
path = lib/third_party/HashLibPlus

cmake/build_helpers.cmake

+8
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,14 @@ macro(addBundledLibraries)
596596
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
597597
endif()
598598

599+
if (NOT USE_SYSTEM_LUNASVG)
600+
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/lunasvg EXCLUDE_FROM_ALL)
601+
set(LUNASVG_LIBRARIES lunasvg)
602+
else()
603+
find_package(LunaSVG REQUIRED)
604+
set(LUNASVG_LIBRARIES lunasvg)
605+
endif()
606+
599607
if (NOT USE_SYSTEM_LLVM)
600608
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
601609
else()

lib/libimhex/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
142142
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
143143
endif()
144144

145-
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES})
145+
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES})
146146

147147
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
148148

lib/libimhex/include/hex/api/achievement_manager.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ namespace hex {
151151
if (m_icon.isValid())
152152
return m_icon;
153153

154-
m_icon = ImGuiExt::Texture(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
154+
m_icon = ImGuiExt::Texture::fromImage(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
155155

156156
return m_icon;
157157
}

lib/libimhex/include/hex/ui/imgui_imhex_extensions.h

+12-5
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,21 @@ namespace ImGuiExt {
7676
};
7777

7878
Texture() = default;
79-
Texture(const ImU8 *buffer, int size, Filter filter = Filter::Nearest, int width = 0, int height = 0);
80-
Texture(std::span<const std::byte> bytes, Filter filter = Filter::Nearest, int width = 0, int height = 0);
81-
explicit Texture(const char *path, Filter filter = Filter::Nearest);
82-
explicit Texture(const std::fs::path &path, Filter filter = Filter::Nearest);
83-
Texture(unsigned int texture, int width, int height);
8479
Texture(const Texture&) = delete;
8580
Texture(Texture&& other) noexcept;
8681

82+
static Texture fromImage(const ImU8 *buffer, int size, Filter filter = Filter::Nearest);
83+
static Texture fromImage(std::span<const std::byte> buffer, Filter filter = Filter::Nearest);
84+
static Texture fromImage(const char *path, Filter filter = Filter::Nearest);
85+
static Texture fromImage(const std::fs::path &path, Filter filter = Filter::Nearest);
86+
static Texture fromGLTexture(unsigned int texture, int width, int height);
87+
static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest);
88+
static Texture fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter = Filter::Nearest);
89+
static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
90+
static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
91+
static Texture fromSVG(std::span<const std::byte> buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest);
92+
93+
8794
~Texture();
8895

8996
Texture& operator=(const Texture&) = delete;

lib/libimhex/source/ui/imgui_imhex_extensions.cpp

+137-43
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
#define STB_IMAGE_IMPLEMENTATION
1313
#include <stb_image.h>
1414

15+
#include <lunasvg.h>
16+
1517
#include <set>
1618
#include <string>
1719

18-
1920
#include <hex/api/imhex_api.hpp>
2021

2122
#include <hex/api/task_manager.hpp>
@@ -40,74 +41,167 @@ namespace ImGuiExt {
4041
return GL_NEAREST;
4142
}
4243

44+
GLuint createTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
45+
GLuint texture;
46+
47+
// Generate texture
48+
glGenTextures(1, &texture);
49+
glBindTexture(GL_TEXTURE_2D, texture);
50+
51+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
52+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
53+
54+
#if defined(GL_UNPACK_ROW_LENGTH)
55+
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
56+
#endif
57+
58+
// Allocate storage for the texture
59+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
60+
61+
return texture;
62+
}
63+
64+
GLuint createMultisampleTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
65+
// Create a regular texture from the RGBA8 array
66+
GLuint texture = createTextureFromRGBA8Array(buffer, width, height, filter);
67+
68+
if (filter == Texture::Filter::Nearest)
69+
return texture;
70+
71+
constexpr static auto SampleCount = 8;
72+
73+
// Generate renderbuffer
74+
GLuint renderbuffer;
75+
glGenRenderbuffers(1, &renderbuffer);
76+
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
77+
glRenderbufferStorageMultisample(GL_RENDERBUFFER, SampleCount, GL_DEPTH24_STENCIL8, width, height);
78+
79+
// Generate framebuffer
80+
GLuint framebuffer;
81+
glGenFramebuffers(1, &framebuffer);
82+
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
83+
84+
// Attach texture to color attachment 0
85+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
86+
87+
// Attach renderbuffer to depth-stencil attachment
88+
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
89+
90+
// Check framebuffer status
91+
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
92+
return 0;
93+
}
94+
95+
// Unbind framebuffer
96+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
97+
98+
return texture;
99+
}
100+
43101
}
44102

45-
Texture::Texture(const ImU8 *buffer, int size, Filter filter, int width, int height) {
103+
Texture Texture::fromImage(const ImU8 *buffer, int size, Filter filter) {
46104
if (size == 0)
47-
return;
105+
return {};
48106

49107
unsigned char *imageData = nullptr;
50108

51-
if (width == 0 || height == 0)
52-
imageData = stbi_load_from_memory(buffer, size, &m_width, &m_height, nullptr, 4);
109+
Texture result;
110+
imageData = stbi_load_from_memory(buffer, size, &result.m_width, &result.m_height, nullptr, 4);
111+
if (imageData == nullptr)
112+
return {};
53113

54-
if (imageData == nullptr) {
55-
if (width * height * 4 > size)
56-
return;
114+
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
57115

58-
imageData = static_cast<unsigned char *>(STBI_MALLOC(size));
59-
std::memcpy(imageData, buffer, size);
60-
m_width = width;
61-
m_height = height;
62-
}
63-
if (imageData == nullptr)
64-
return;
116+
STBI_FREE(imageData);
65117

66-
GLuint texture;
67-
glGenTextures(1, &texture);
68-
glBindTexture(GL_TEXTURE_2D, texture);
118+
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
69119

70-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
71-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
120+
return result;
121+
}
122+
123+
Texture Texture::fromImage(std::span<const std::byte> buffer, Filter filter) {
124+
return Texture::fromImage(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), filter);
125+
}
126+
127+
128+
Texture Texture::fromImage(const std::fs::path &path, Filter filter) {
129+
return Texture::fromImage(wolv::util::toUTF8String(path).c_str(), filter);
130+
}
72131

73-
#if defined(GL_UNPACK_ROW_LENGTH)
74-
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
75-
#endif
132+
Texture Texture::fromImage(const char *path, Filter filter) {
133+
Texture result;
134+
unsigned char *imageData = stbi_load(path, &result.m_width, &result.m_height, nullptr, 4);
135+
if (imageData == nullptr)
136+
return {};
137+
138+
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
76139

77-
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
78140
STBI_FREE(imageData);
79141

80-
m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
142+
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
143+
144+
return result;
81145
}
82146

83-
Texture::Texture(std::span<const std::byte> bytes, Filter filter, int width, int height) : Texture(reinterpret_cast<const ImU8*>(bytes.data()), bytes.size(), filter, width, height) { }
147+
Texture Texture::fromGLTexture(unsigned int glTexture, int width, int height) {
148+
Texture texture;
149+
texture.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(glTexture));
150+
texture.m_width = width;
151+
texture.m_height = height;
84152

85-
Texture::Texture(const std::fs::path &path, Filter filter) : Texture(reinterpret_cast<const char *>(path.u8string().c_str()), filter) { }
153+
return texture;
154+
}
86155

87-
Texture::Texture(const char *path, Filter filter) {
88-
unsigned char *imageData = stbi_load(path, &m_width, &m_height, nullptr, 4);
89-
if (imageData == nullptr)
90-
return;
156+
Texture Texture::fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter) {
157+
return Texture::fromBitmap(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), width, height, filter);
158+
}
91159

92-
GLuint texture;
93-
glGenTextures(1, &texture);
94-
glBindTexture(GL_TEXTURE_2D, texture);
160+
Texture Texture::fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter) {
161+
if (width * height * 4 > size)
162+
return {};
95163

96-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
97-
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
164+
GLuint texture = createMultisampleTextureFromRGBA8Array(buffer, width, height, filter);
98165

99-
#if defined(GL_UNPACK_ROW_LENGTH)
100-
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
101-
#endif
166+
Texture result;
167+
result.m_width = width;
168+
result.m_height = height;
169+
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
102170

103-
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
104-
STBI_FREE(imageData);
171+
return result;
172+
}
173+
174+
Texture Texture::fromSVG(const char *path, int width, int height, Filter filter) {
175+
auto document = lunasvg::Document::loadFromFile(path);
176+
auto bitmap = document->renderToBitmap(width, height);
177+
178+
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
179+
180+
Texture result;
181+
result.m_width = bitmap.width();
182+
result.m_height = bitmap.height();
183+
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
105184

106-
m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
185+
return result;
186+
}
187+
188+
Texture Texture::fromSVG(const std::fs::path &path, int width, int height, Filter filter) {
189+
return Texture::fromSVG(wolv::util::toUTF8String(path).c_str(), width, height, filter);
107190
}
108191

109-
Texture::Texture(unsigned int texture, int width, int height) : m_textureId(reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture))), m_width(width), m_height(height) {
192+
Texture Texture::fromSVG(std::span<const std::byte> buffer, int width, int height, Filter filter) {
193+
auto document = lunasvg::Document::loadFromData(reinterpret_cast<const char*>(buffer.data()), buffer.size());
194+
auto bitmap = document->renderToBitmap(width, height);
195+
bitmap.convertToRGBA();
110196

197+
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
198+
199+
Texture result;
200+
result.m_width = bitmap.width();
201+
result.m_height = bitmap.height();
202+
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
203+
204+
return result;
111205
}
112206

113207
Texture::Texture(Texture&& other) noexcept {

lib/third_party/lunasvg

Submodule lunasvg added at 17b595a

main/gui/source/init/splash_window.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,8 @@ namespace hex::init {
521521
void WindowSplash::loadAssets() {
522522

523523
// Load splash screen image from romfs
524-
this->splashBackgroundTexture = ImGuiExt::Texture(romfs::get("splash_background.png").span(), ImGuiExt::Texture::Filter::Linear);
525-
this->splashTextTexture = ImGuiExt::Texture(romfs::get("splash_text.png").span(), ImGuiExt::Texture::Filter::Linear);
524+
this->splashBackgroundTexture = ImGuiExt::Texture::fromImage(romfs::get("splash_background.png").span(), ImGuiExt::Texture::Filter::Linear);
525+
this->splashTextTexture = ImGuiExt::Texture::fromImage(romfs::get("splash_text.png").span(), ImGuiExt::Texture::Filter::Linear);
526526

527527
// If the image couldn't be loaded correctly, something went wrong during the build process
528528
// Close the application since this would lead to errors later on anyway.

plugins/builtin/include/content/helpers/diagrams.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ namespace hex {
129129
pixel = ImAlphaBlendColors(pixel, ImColor(color));
130130
}
131131

132-
m_texture = ImGuiExt::Texture(reinterpret_cast<u8*>(pixels.data()), pixels.size() * 4, m_filter, 0xFF, 0xFF);
132+
m_texture = ImGuiExt::Texture::fromBitmap(reinterpret_cast<u8*>(pixels.data()), pixels.size() * 4, 0xFF, 0xFF, m_filter);
133133
m_textureValid = m_texture.isValid();
134134
}
135135
}
@@ -252,7 +252,7 @@ namespace hex {
252252
pixel = ImAlphaBlendColors(pixel, ImColor(color));
253253
}
254254

255-
m_texture = ImGuiExt::Texture(reinterpret_cast<u8*>(pixels.data()), pixels.size() * 4, m_filter, 0xFF, 0xFF);
255+
m_texture = ImGuiExt::Texture::fromBitmap(reinterpret_cast<u8*>(pixels.data()), pixels.size() * 4, 0xFF, 0xFF, m_filter);
256256
m_textureValid = m_texture.isValid();
257257
}
258258
}
-118 KB
Binary file not shown.

0 commit comments

Comments
 (0)