#include "pixmap.hpp" #include namespace t5de { namespace { using Getter = unsigned(__thiscall*)(const imvu::Pixmap*); using PixelsGetter = std::uint32_t*(__thiscall*)(const imvu::Pixmap*); using SizeConstructor = imvu::Pixmap*(__thiscall*)(void*, int, int); using DefaultConstructor = imvu::Pixmap*(__thiscall*)(void*); using CopyConstructor = imvu::Pixmap*(__thiscall*)(void*, const imvu::Pixmap*); using Destructor = void(__thiscall*)(imvu::Pixmap*); struct Methods { Getter width = nullptr; Getter height = nullptr; Getter rowBytes = nullptr; PixelsGetter pixels = nullptr; SizeConstructor construct = nullptr; DefaultConstructor constructEmpty = nullptr; CopyConstructor copy = nullptr; Destructor destroy = nullptr; }; const Methods& methods() { static const Methods methods = [] { Methods found; if (HMODULE module = GetModuleHandleW(L"pixmap.dll")) { found.width = reinterpret_cast(GetProcAddress(module, "?width@Pixmap@@QBEIXZ")); found.height = reinterpret_cast(GetProcAddress(module, "?height@Pixmap@@QBEIXZ")); found.rowBytes = reinterpret_cast(GetProcAddress(module, "?rowBytes@Pixmap@@QBEIXZ")); found.pixels = reinterpret_cast(GetProcAddress(module, "?pixels@Pixmap@@QBEPAIXZ")); found.construct = reinterpret_cast(GetProcAddress(module, "??0Pixmap@@QAE@HH@Z")); found.constructEmpty = reinterpret_cast(GetProcAddress(module, "??0Pixmap@@QAE@XZ")); found.copy = reinterpret_cast(GetProcAddress(module, "??0Pixmap@@QAE@ABV0@@Z")); found.destroy = reinterpret_cast(GetProcAddress(module, "??1Pixmap@@QAE@XZ")); } return found; }(); return methods; } } // namespace std::optional pixmap_pixels(const imvu::Pixmap& pixmap) { const Methods& m = methods(); if (m.width == nullptr || m.height == nullptr || m.rowBytes == nullptr || m.pixels == nullptr) { return std::nullopt; } return PixmapPixels{m.width(&pixmap), m.height(&pixmap), m.rowBytes(&pixmap), m.pixels(&pixmap)}; } OwnedPixmap::OwnedPixmap(int width, int height) { const Methods& m = methods(); if (m.construct != nullptr && m.constructEmpty != nullptr && m.copy != nullptr && m.destroy != nullptr) { m.construct(storage_, width, height); valid_ = true; } } OwnedPixmap::~OwnedPixmap() { if (valid_) { methods().destroy(reinterpret_cast(storage_)); } } imvu::Pixmap* OwnedPixmap::copyTo(imvu::Pixmap* result) const { const Methods& m = methods(); if (valid_) { return m.copy(result, &get()); } // Without pixmap.dll's methods there's nothing to construct one with (IMVU's own code would have failed already). return m.constructEmpty != nullptr ? m.constructEmpty(result) : result; } } // namespace t5de