Animated thumbnails now show a small play-arrow badge (bottom-right) so users can spot which images move before hovering; it's hidden while the image plays on hover. Detection is cheap — a new util::IsAnimatedImageFile probes without a full decode: animated WebP via WebPGetFeatures.has_animation, and a multi-frame GIF via a lightweight image-descriptor block walk (stops at the 2nd frame). The picker only probes .gif/.webp thumbnails and caches the result on the Thumb. Verified: animated GIF + animated WebP report animated; still GIF/WebP/PNG do not. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
109 lines
4.1 KiB
C++
109 lines
4.1 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
|
|
#pragma once
|
|
|
|
#include "imgui.h"
|
|
|
|
#include <vector>
|
|
|
|
namespace dragonx {
|
|
namespace util {
|
|
|
|
/**
|
|
* @brief Downscaled RGBA frame sequence for an image (1 frame for stills, N for animations).
|
|
*/
|
|
struct AnimFrames {
|
|
std::vector<std::vector<unsigned char>> frames; ///< each is w*h*4 RGBA (already downscaled)
|
|
std::vector<float> delaysSec; ///< per-frame duration in seconds (parallel to frames)
|
|
int w = 0;
|
|
int h = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief Decode an image into 1+ downscaled RGBA frames plus per-frame durations.
|
|
*
|
|
* Animated GIF (via stb) and animated WebP (via libwebp WebPAnimDecoder) return every frame (capped at
|
|
* maxFrames); static formats — and APNG, which stb reads as a single image — return one frame. Frames
|
|
* are box-downscaled internally (smaller for animations to bound VRAM). The caller uploads each frame
|
|
* with CreateRawTexture. Returns false on decode failure.
|
|
*/
|
|
bool LoadAnimatedRGBA(const char* path, int maxFrames, AnimFrames& out);
|
|
|
|
/**
|
|
* @brief Cheaply report whether an image file is an animation (multi-frame GIF or animated WebP),
|
|
* WITHOUT a full decode — a header/structure probe. False for stills + non-animatable formats.
|
|
*/
|
|
bool IsAnimatedImageFile(const char* path);
|
|
|
|
/**
|
|
* @brief Load a PNG/JPG/BMP image from disk into an OpenGL or DX11 texture.
|
|
* @param path File path (relative to working directory or absolute)
|
|
* @param outTexID Receives the ImTextureID for ImGui rendering
|
|
* @param outW Receives image width
|
|
* @param outH Receives image height
|
|
* @return true on success
|
|
*
|
|
* The caller is responsible for destroying the texture.
|
|
* On OpenGL, cast outTexID to GLuint and call glDeleteTextures.
|
|
*/
|
|
bool LoadTextureFromFile(const char* path, ImTextureID* outTexID, int* outW, int* outH);
|
|
|
|
/**
|
|
* @brief Load a PNG/JPG/BMP image from memory into an OpenGL or DX11 texture.
|
|
* @param data Pointer to compressed image data (e.g. PNG bytes)
|
|
* @param dataSize Size of the data in bytes
|
|
* @param outTexID Receives the ImTextureID for ImGui rendering
|
|
* @param outW Receives image width
|
|
* @param outH Receives image height
|
|
* @return true on success
|
|
*/
|
|
bool LoadTextureFromMemory(const unsigned char* data, size_t dataSize,
|
|
ImTextureID* outTexID, int* outW, int* outH);
|
|
|
|
/**
|
|
* @brief Create a texture from raw RGBA pixel data (no decoding needed).
|
|
* @param pixels Pointer to RGBA pixel data (4 bytes per pixel, caller-owned)
|
|
* @param w Image width
|
|
* @param h Image height
|
|
* @param repeat If true, set wrap mode to GL_REPEAT (for tiling); else CLAMP_TO_EDGE
|
|
* @param outTexID Receives the ImTextureID
|
|
* @return true on success
|
|
*/
|
|
bool CreateRawTexture(const unsigned char* pixels, int w, int h,
|
|
bool repeat, ImTextureID* outTexID);
|
|
|
|
/**
|
|
* @brief Load raw RGBA pixel data from a PNG/JPG/BMP file (no GPU texture).
|
|
* @param path File path
|
|
* @param outW Receives image width
|
|
* @param outH Receives image height
|
|
* @return Pointer to RGBA pixels (caller must free with FreeRawPixels), or nullptr on failure
|
|
*/
|
|
unsigned char* LoadRawPixelsFromFile(const char* path, int* outW, int* outH);
|
|
|
|
/**
|
|
* @brief Load raw RGBA pixel data from in-memory compressed image data (no GPU texture).
|
|
* @param data Pointer to compressed image data (e.g. PNG bytes)
|
|
* @param dataSize Size of the data in bytes
|
|
* @param outW Receives image width
|
|
* @param outH Receives image height
|
|
* @return Pointer to RGBA pixels (caller must free with FreeRawPixels), or nullptr on failure
|
|
*/
|
|
unsigned char* LoadRawPixelsFromMemory(const unsigned char* data, size_t dataSize, int* outW, int* outH);
|
|
|
|
/**
|
|
* @brief Free pixels returned by LoadRawPixelsFromFile / LoadRawPixelsFromMemory.
|
|
*/
|
|
void FreeRawPixels(unsigned char* pixels);
|
|
|
|
/**
|
|
* @brief Destroy a GPU texture previously created by Load/CreateRaw functions.
|
|
* @param texID Texture handle (GLuint on OpenGL, ID3D11ShaderResourceView* on DX11)
|
|
*/
|
|
void DestroyTexture(ImTextureID texID);
|
|
|
|
} // namespace util
|
|
} // namespace dragonx
|