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:
2026-02-26 02:31:52 -06:00
commit 3aee55b49c
306 changed files with 177789 additions and 0 deletions

View File

@@ -0,0 +1,302 @@
// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "framebuffer.h"
#ifdef DRAGONX_HAS_GLAD
#include <glad/gl.h>
#include <cstdio>
#include "../../util/logger.h"
// GL 3.0 constants — may be missing from some GLAD configurations
#ifndef GL_RGBA16F
#define GL_RGBA16F 0x881A
#endif
#ifndef GL_HALF_FLOAT
#define GL_HALF_FLOAT 0x140B
#endif
namespace dragonx {
namespace ui {
namespace effects {
// ============================================================================
// Framebuffer Implementation (GLEW Available)
// ============================================================================
Framebuffer::Framebuffer() = default;
Framebuffer::~Framebuffer()
{
destroy();
}
Framebuffer::Framebuffer(Framebuffer&& other) noexcept
: fbo_(other.fbo_)
, colorTexture_(other.colorTexture_)
, depthRbo_(other.depthRbo_)
, width_(other.width_)
, height_(other.height_)
, isComplete_(other.isComplete_)
{
other.fbo_ = 0;
other.colorTexture_ = 0;
other.depthRbo_ = 0;
other.width_ = 0;
other.height_ = 0;
other.isComplete_ = false;
}
Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept
{
if (this != &other) {
destroy();
fbo_ = other.fbo_;
colorTexture_ = other.colorTexture_;
depthRbo_ = other.depthRbo_;
width_ = other.width_;
height_ = other.height_;
isComplete_ = other.isComplete_;
other.fbo_ = 0;
other.colorTexture_ = 0;
other.depthRbo_ = 0;
other.width_ = 0;
other.height_ = 0;
other.isComplete_ = false;
}
return *this;
}
bool Framebuffer::init(int width, int height, bool useFloat16)
{
if (width <= 0 || height <= 0) {
DEBUG_LOGF("Framebuffer::init - Invalid dimensions: %dx%d\n", width, height);
return false;
}
// Clean up existing resources
cleanup();
width_ = width;
height_ = height;
useFloat16_ = useFloat16;
// Generate framebuffer
glGenFramebuffers(1, &fbo_);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
// Create color texture — use RGBA16F for blur intermediates to avoid banding
glGenTextures(1, &colorTexture_);
glBindTexture(GL_TEXTURE_2D, colorTexture_);
if (useFloat16) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_HALF_FLOAT, nullptr);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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);
// Attach color texture to framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture_, 0);
// Create depth renderbuffer (optional, but good for completeness)
glGenRenderbuffers(1, &depthRbo_);
glBindRenderbuffer(GL_RENDERBUFFER, depthRbo_);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRbo_);
// Check completeness
isComplete_ = checkComplete();
// Unbind
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (!isComplete_) {
DEBUG_LOGF("Framebuffer::init - Framebuffer is not complete!\n");
cleanup();
return false;
}
return true;
}
bool Framebuffer::resize(int width, int height)
{
if (width == width_ && height == height_) {
return true; // No change needed
}
return init(width, height, useFloat16_);
}
void Framebuffer::destroy()
{
cleanup();
}
void Framebuffer::cleanup()
{
if (colorTexture_) {
glDeleteTextures(1, &colorTexture_);
colorTexture_ = 0;
}
if (depthRbo_) {
glDeleteRenderbuffers(1, &depthRbo_);
depthRbo_ = 0;
}
if (fbo_) {
glDeleteFramebuffers(1, &fbo_);
fbo_ = 0;
}
width_ = 0;
height_ = 0;
isComplete_ = false;
}
bool Framebuffer::checkComplete()
{
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
const char* errorStr = "Unknown";
switch (status) {
case GL_FRAMEBUFFER_UNDEFINED: errorStr = "UNDEFINED"; break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: errorStr = "INCOMPLETE_ATTACHMENT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: errorStr = "INCOMPLETE_MISSING_ATTACHMENT"; break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: errorStr = "INCOMPLETE_DRAW_BUFFER"; break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: errorStr = "INCOMPLETE_READ_BUFFER"; break;
case GL_FRAMEBUFFER_UNSUPPORTED: errorStr = "UNSUPPORTED"; break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: errorStr = "INCOMPLETE_MULTISAMPLE"; break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: errorStr = "INCOMPLETE_LAYER_TARGETS"; break;
}
DEBUG_LOGF("Framebuffer error: %s (0x%X)\n", errorStr, status);
return false;
}
return true;
}
void Framebuffer::bind()
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
glViewport(0, 0, width_, height_);
}
void Framebuffer::unbind()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Framebuffer::clear(float r, float g, float b, float a)
{
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Framebuffer::blitFrom(GLuint srcFbo, int srcX, int srcY, int srcWidth, int srcHeight,
int dstX, int dstY)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_);
glBlitFramebuffer(
srcX, srcY, srcX + srcWidth, srcY + srcHeight, // Source rect
dstX, dstY, dstX + srcWidth, dstY + srcHeight, // Dest rect
GL_COLOR_BUFFER_BIT,
GL_LINEAR
);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Framebuffer::captureScreen(int viewportWidth, int viewportHeight)
{
// Blit from default framebuffer (0) to this framebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_);
glBlitFramebuffer(
0, 0, viewportWidth, viewportHeight, // Source (screen)
0, 0, width_, height_, // Dest (this FBO)
GL_COLOR_BUFFER_BIT,
GL_LINEAR
);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// ============================================================================
// FramebufferPingPong Implementation
// ============================================================================
bool FramebufferPingPong::init(int width, int height, bool useFloat16)
{
if (!buffers_[0].init(width, height, useFloat16)) return false;
if (!buffers_[1].init(width, height, useFloat16)) return false;
currentSource_ = 0;
return true;
}
bool FramebufferPingPong::resize(int width, int height)
{
if (!buffers_[0].resize(width, height)) return false;
if (!buffers_[1].resize(width, height)) return false;
return true;
}
void FramebufferPingPong::destroy()
{
buffers_[0].destroy();
buffers_[1].destroy();
currentSource_ = 0;
}
void FramebufferPingPong::swap()
{
currentSource_ = 1 - currentSource_;
}
} // namespace effects
} // namespace ui
} // namespace dragonx
#else // !DRAGONX_HAS_GLAD
// ============================================================================
// Stub Implementation (No GLAD - Acrylic effects disabled)
// ============================================================================
namespace dragonx {
namespace ui {
namespace effects {
Framebuffer::Framebuffer() = default;
Framebuffer::~Framebuffer() = default;
Framebuffer::Framebuffer(Framebuffer&&) noexcept = default;
Framebuffer& Framebuffer::operator=(Framebuffer&&) noexcept = default;
bool Framebuffer::init(int, int, bool) { return false; }
bool Framebuffer::resize(int, int) { return false; }
void Framebuffer::destroy() {}
void Framebuffer::cleanup() {}
bool Framebuffer::checkComplete() { return false; }
void Framebuffer::bind() {}
void Framebuffer::unbind() {}
void Framebuffer::clear(float, float, float, float) {}
void Framebuffer::blitFrom(unsigned int, int, int, int, int, int, int) {}
void Framebuffer::captureScreen(int, int) {}
bool FramebufferPingPong::init(int, int, bool) { return false; }
bool FramebufferPingPong::resize(int, int) { return false; }
void FramebufferPingPong::destroy() {}
void FramebufferPingPong::swap() {}
} // namespace effects
} // namespace ui
} // namespace dragonx
#endif // DRAGONX_HAS_GLAD