ObsidianDragon - DragonX ImGui Wallet
Full-node GUI wallet for DragonX cryptocurrency. Built with Dear ImGui, SDL3, and OpenGL3/DX11. Features: - Send/receive shielded and transparent transactions - Autoshield with merged transaction display - Built-in CPU mining (xmrig) - Peer management and network monitoring - Wallet encryption with PIN lock - QR code generation for receive addresses - Transaction history with pagination - Console for direct RPC commands - Cross-platform (Linux, Windows)
This commit is contained in:
326
src/util/texture_loader.cpp
Normal file
326
src/util/texture_loader.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "texture_loader.h"
|
||||
|
||||
// stb_image — single-file image loader (public domain)
|
||||
// Only compiled here; all other files just include the header.
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_ONLY_PNG
|
||||
#define STBI_NO_STDIO // we do our own fread for portability
|
||||
#include "stb_image.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
#include <d3d11.h>
|
||||
|
||||
// Get D3D11 device from ImGui backend (same pattern as qr_code.cpp)
|
||||
static ID3D11Device* GetImGuiD3D11Device()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (!io.BackendRendererUserData) return nullptr;
|
||||
return *reinterpret_cast<ID3D11Device**>(io.BackendRendererUserData);
|
||||
}
|
||||
#else
|
||||
#ifdef DRAGONX_HAS_GLAD
|
||||
#include <glad/gl.h>
|
||||
#else
|
||||
#include <SDL3/SDL_opengl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "../util/logger.h"
|
||||
|
||||
namespace dragonx {
|
||||
namespace util {
|
||||
|
||||
// Read entire file into memory
|
||||
static bool ReadFileToBuffer(const char* path, std::vector<unsigned char>& buf)
|
||||
{
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (!f) return false;
|
||||
fseek(f, 0, SEEK_END);
|
||||
long sz = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
if (sz <= 0) { fclose(f); return false; }
|
||||
buf.resize((size_t)sz);
|
||||
size_t rd = fread(buf.data(), 1, (size_t)sz, f);
|
||||
fclose(f);
|
||||
return rd == (size_t)sz;
|
||||
}
|
||||
|
||||
bool LoadTextureFromFile(const char* path, ImTextureID* outTexID, int* outW, int* outH)
|
||||
{
|
||||
std::vector<unsigned char> fileData;
|
||||
if (!ReadFileToBuffer(path, fileData)) {
|
||||
DEBUG_LOGF("LoadTextureFromFile: failed to read '%s'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
int w = 0, h = 0, channels = 0;
|
||||
unsigned char* pixels = stbi_load_from_memory(
|
||||
fileData.data(), (int)fileData.size(), &w, &h, &channels, 4);
|
||||
if (!pixels) {
|
||||
DEBUG_LOGF("LoadTextureFromFile: stbi failed for '%s'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
ID3D11Device* device = GetImGuiD3D11Device();
|
||||
if (!device) {
|
||||
stbi_image_free(pixels);
|
||||
DEBUG_LOGF("LoadTextureFromFile: no D3D11 device available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
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;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData = {};
|
||||
initData.pSysMem = pixels;
|
||||
initData.SysMemPitch = w * 4;
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, &initData, &texture);
|
||||
stbi_image_free(pixels);
|
||||
if (FAILED(hr) || !texture) {
|
||||
DEBUG_LOGF("LoadTextureFromFile: CreateTexture2D failed for '%s'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = desc.Format;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device->CreateShaderResourceView(texture, &srvDesc, &srv);
|
||||
texture->Release();
|
||||
if (FAILED(hr) || !srv) {
|
||||
DEBUG_LOGF("LoadTextureFromFile: CreateSRV failed for '%s'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
*outTexID = (ImTextureID)(intptr_t)srv;
|
||||
*outW = w;
|
||||
*outH = h;
|
||||
DEBUG_LOGF("LoadTextureFromFile: loaded '%s' (%dx%d) -> DX11 SRV %p\n", path, w, h, (void*)srv);
|
||||
return true;
|
||||
#else
|
||||
|
||||
GLuint tex = 0;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
stbi_image_free(pixels);
|
||||
|
||||
*outTexID = (ImTextureID)(intptr_t)tex;
|
||||
*outW = w;
|
||||
*outH = h;
|
||||
DEBUG_LOGF("LoadTextureFromFile: loaded '%s' (%dx%d) -> texture %u\n", path, w, h, tex);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LoadTextureFromMemory(const unsigned char* data, size_t dataSize,
|
||||
ImTextureID* outTexID, int* outW, int* outH)
|
||||
{
|
||||
if (!data || dataSize == 0) {
|
||||
DEBUG_LOGF("LoadTextureFromMemory: null/empty data\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int w = 0, h = 0, channels = 0;
|
||||
unsigned char* pixels = stbi_load_from_memory(
|
||||
data, (int)dataSize, &w, &h, &channels, 4);
|
||||
if (!pixels) {
|
||||
DEBUG_LOGF("LoadTextureFromMemory: stbi decode failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
ID3D11Device* device = GetImGuiD3D11Device();
|
||||
if (!device) {
|
||||
stbi_image_free(pixels);
|
||||
DEBUG_LOGF("LoadTextureFromMemory: no D3D11 device available\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
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;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData = {};
|
||||
initData.pSysMem = pixels;
|
||||
initData.SysMemPitch = w * 4;
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, &initData, &texture);
|
||||
stbi_image_free(pixels);
|
||||
if (FAILED(hr) || !texture) {
|
||||
DEBUG_LOGF("LoadTextureFromMemory: CreateTexture2D failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = desc.Format;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device->CreateShaderResourceView(texture, &srvDesc, &srv);
|
||||
texture->Release();
|
||||
if (FAILED(hr) || !srv) {
|
||||
DEBUG_LOGF("LoadTextureFromMemory: CreateSRV failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
*outTexID = (ImTextureID)(intptr_t)srv;
|
||||
*outW = w;
|
||||
*outH = h;
|
||||
DEBUG_LOGF("LoadTextureFromMemory: %dx%d -> DX11 SRV %p\n", w, h, (void*)srv);
|
||||
return true;
|
||||
#else
|
||||
GLuint tex = 0;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
stbi_image_free(pixels);
|
||||
|
||||
*outTexID = (ImTextureID)(intptr_t)tex;
|
||||
*outW = w;
|
||||
*outH = h;
|
||||
DEBUG_LOGF("LoadTextureFromMemory: %dx%d -> texture %u\n", w, h, tex);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CreateRawTexture(const unsigned char* pixels, int w, int h,
|
||||
bool repeat, ImTextureID* outTexID)
|
||||
{
|
||||
if (!pixels || w <= 0 || h <= 0) return false;
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
ID3D11Device* device = GetImGuiD3D11Device();
|
||||
if (!device) return false;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = w;
|
||||
desc.Height = h;
|
||||
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;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData = {};
|
||||
initData.pSysMem = pixels;
|
||||
initData.SysMemPitch = w * 4;
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, &initData, &texture);
|
||||
if (FAILED(hr) || !texture) return false;
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = desc.Format;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
hr = device->CreateShaderResourceView(texture, &srvDesc, &srv);
|
||||
texture->Release();
|
||||
if (FAILED(hr) || !srv) return false;
|
||||
|
||||
*outTexID = (ImTextureID)(intptr_t)srv;
|
||||
return true;
|
||||
#else
|
||||
GLuint tex = 0;
|
||||
glGenTextures(1, &tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (repeat) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
*outTexID = (ImTextureID)(intptr_t)tex;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned char* LoadRawPixelsFromFile(const char* path, int* outW, int* outH)
|
||||
{
|
||||
std::vector<unsigned char> fileData;
|
||||
if (!ReadFileToBuffer(path, fileData)) return nullptr;
|
||||
int channels = 0;
|
||||
return stbi_load_from_memory(fileData.data(), (int)fileData.size(),
|
||||
outW, outH, &channels, 4);
|
||||
}
|
||||
|
||||
unsigned char* LoadRawPixelsFromMemory(const unsigned char* data, size_t dataSize, int* outW, int* outH)
|
||||
{
|
||||
if (!data || dataSize == 0) return nullptr;
|
||||
int channels = 0;
|
||||
return stbi_load_from_memory(data, (int)dataSize, outW, outH, &channels, 4);
|
||||
}
|
||||
|
||||
void FreeRawPixels(unsigned char* pixels)
|
||||
{
|
||||
if (pixels) stbi_image_free(pixels);
|
||||
}
|
||||
|
||||
void DestroyTexture(ImTextureID texID)
|
||||
{
|
||||
if (!texID) return;
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
auto* srv = (ID3D11ShaderResourceView*)(intptr_t)texID;
|
||||
srv->Release();
|
||||
#else
|
||||
GLuint tex = (GLuint)(intptr_t)texID;
|
||||
glDeleteTextures(1, &tex);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user