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)
169 lines
5.1 KiB
C++
169 lines
5.1 KiB
C++
// DragonX Wallet - ImGui Edition
|
||
// Copyright 2024-2026 The Hush Developers
|
||
// Released under the GPLv3
|
||
|
||
#include "noise_texture.h"
|
||
#include "texture_loader.h"
|
||
#include <cstdlib>
|
||
#include <cstring>
|
||
|
||
namespace dragonx {
|
||
namespace util {
|
||
|
||
static constexpr int kNoiseSize = 256;
|
||
|
||
ImTextureID GetNoiseTexture(int* texSize)
|
||
{
|
||
static ImTextureID s_tex = 0;
|
||
static bool s_init = false;
|
||
|
||
if (texSize) *texSize = kNoiseSize;
|
||
|
||
if (s_init) return s_tex;
|
||
s_init = true;
|
||
|
||
// Generate subtle white-noise RGBA pixels.
|
||
// Each pixel is white (RGB=255) with alpha in a narrow band
|
||
// around 128 so the grain is uniform and gentle.
|
||
const int numPixels = kNoiseSize * kNoiseSize;
|
||
unsigned char* pixels = (unsigned char*)malloc(numPixels * 4);
|
||
if (!pixels) return 0;
|
||
|
||
// Simple LCG PRNG (deterministic, fast, no need for crypto quality)
|
||
unsigned int seed = 0xDEADBEEF;
|
||
for (int i = 0; i < numPixels; ++i) {
|
||
seed = seed * 1664525u + 1013904223u;
|
||
// Range: 16–240 (centered on 128, ±112) for visible, high-contrast grain
|
||
unsigned char v = 16 + (unsigned char)((seed >> 24) % 225);
|
||
pixels[i * 4 + 0] = 255; // R
|
||
pixels[i * 4 + 1] = 255; // G
|
||
pixels[i * 4 + 2] = 255; // B
|
||
pixels[i * 4 + 3] = v; // A — high contrast variation
|
||
}
|
||
|
||
bool ok = CreateRawTexture(pixels, kNoiseSize, kNoiseSize,
|
||
true /* repeat/tile */, &s_tex);
|
||
free(pixels);
|
||
|
||
if (!ok) {
|
||
s_tex = 0;
|
||
}
|
||
return s_tex;
|
||
}
|
||
|
||
// ============================================================================
|
||
// Pre-tiled viewport-sized noise texture
|
||
// ============================================================================
|
||
|
||
// Generate the base 256x256 noise pattern into a caller-allocated buffer.
|
||
// Same deterministic LCG as GetNoiseTexture().
|
||
static void GenerateBaseNoise(unsigned char* out, int sz)
|
||
{
|
||
unsigned int seed = 0xDEADBEEF;
|
||
const int numPixels = sz * sz;
|
||
for (int i = 0; i < numPixels; ++i) {
|
||
seed = seed * 1664525u + 1013904223u;
|
||
unsigned char v = 16 + (unsigned char)((seed >> 24) % 225);
|
||
out[i * 4 + 0] = 255;
|
||
out[i * 4 + 1] = 255;
|
||
out[i * 4 + 2] = 255;
|
||
out[i * 4 + 3] = v;
|
||
}
|
||
}
|
||
|
||
ImTextureID GetTiledNoiseTexture(int viewportW, int viewportH,
|
||
int* outW, int* outH)
|
||
{
|
||
static ImTextureID s_tex = 0;
|
||
static int s_texW = 0;
|
||
static int s_texH = 0;
|
||
|
||
if (outW) *outW = s_texW;
|
||
if (outH) *outH = s_texH;
|
||
|
||
// Re-use if viewport hasn't changed
|
||
if (s_tex && s_texW == viewportW && s_texH == viewportH) {
|
||
return s_tex;
|
||
}
|
||
|
||
// Destroy old texture
|
||
if (s_tex) {
|
||
DestroyTexture(s_tex);
|
||
s_tex = 0;
|
||
s_texW = s_texH = 0;
|
||
}
|
||
|
||
if (viewportW <= 0 || viewportH <= 0) return 0;
|
||
|
||
// Generate base tile
|
||
unsigned char* base = (unsigned char*)malloc(kNoiseSize * kNoiseSize * 4);
|
||
if (!base) return 0;
|
||
GenerateBaseNoise(base, kNoiseSize);
|
||
|
||
// Allocate viewport-sized buffer and tile the base pattern
|
||
const size_t rowBytes = (size_t)viewportW * 4;
|
||
unsigned char* tiled = (unsigned char*)malloc(rowBytes * viewportH);
|
||
if (!tiled) { free(base); return 0; }
|
||
|
||
const int basePitch = kNoiseSize * 4;
|
||
for (int y = 0; y < viewportH; ++y) {
|
||
int sy = y % kNoiseSize;
|
||
unsigned char* dst = tiled + y * rowBytes;
|
||
const unsigned char* srcRow = base + sy * basePitch;
|
||
int x = 0;
|
||
// Copy full tile-width strips
|
||
while (x + kNoiseSize <= viewportW) {
|
||
memcpy(dst + x * 4, srcRow, basePitch);
|
||
x += kNoiseSize;
|
||
}
|
||
// Partial remaining strip
|
||
if (x < viewportW) {
|
||
memcpy(dst + x * 4, srcRow, (viewportW - x) * 4);
|
||
}
|
||
}
|
||
free(base);
|
||
|
||
bool ok = CreateRawTexture(tiled, viewportW, viewportH,
|
||
false /* no repeat needed */, &s_tex);
|
||
free(tiled);
|
||
|
||
if (ok) {
|
||
s_texW = viewportW;
|
||
s_texH = viewportH;
|
||
} else {
|
||
s_tex = 0;
|
||
}
|
||
|
||
if (outW) *outW = s_texW;
|
||
if (outH) *outH = s_texH;
|
||
return s_tex;
|
||
}
|
||
|
||
void DrawTiledNoiseRect(ImDrawList* dl, const ImVec2& pMin, const ImVec2& pMax,
|
||
ImU32 tintColor)
|
||
{
|
||
if (!dl || (tintColor & IM_COL32_A_MASK) == 0) return;
|
||
|
||
ImGuiViewport* vp = ImGui::GetMainViewport();
|
||
int vpW = (int)vp->Size.x;
|
||
int vpH = (int)vp->Size.y;
|
||
if (vpW <= 0 || vpH <= 0) return;
|
||
|
||
int texW = 0, texH = 0;
|
||
ImTextureID tex = GetTiledNoiseTexture(vpW, vpH, &texW, &texH);
|
||
if (!tex || texW <= 0 || texH <= 0) return;
|
||
|
||
// Compute UVs: map screen-space rect to texture coordinates.
|
||
// The tiled texture covers the entire viewport, so UV = screenPos / vpSize.
|
||
// Subtract viewport origin for multi-viewport support.
|
||
float u0 = (pMin.x - vp->Pos.x) / (float)texW;
|
||
float v0 = (pMin.y - vp->Pos.y) / (float)texH;
|
||
float u1 = (pMax.x - vp->Pos.x) / (float)texW;
|
||
float v1 = (pMax.y - vp->Pos.y) / (float)texH;
|
||
|
||
dl->AddImage(tex, pMin, pMax, ImVec2(u0, v0), ImVec2(u1, v1), tintColor);
|
||
}
|
||
|
||
} // namespace util
|
||
} // namespace dragonx
|