CI / build (push) Successful in 48s
While the renderer process runs, the adapter makes the client's render targets itself and the renderer process draws frames into them: texture targets are drawn with like any texture, and a pixmap target's frame is read back through the channel into its Pixmap (protocol version 4: BeginFrame names its target, CreateRenderTarget, Channel::readSize and the -read event). Frames into render targets are drawn even while the window is hidden. The client uses pixmap targets for snapshots (outfit pictures, photos), checked to look right. The render target interfaces are declared from IMVU's vtables. Co-Authored-By: Claude Opus 5.5 <[email protected]>
84 lines
2.9 KiB
C++
84 lines
2.9 KiB
C++
#include "pixmap.hpp"
|
|
|
|
#include <windows.h>
|
|
|
|
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<Getter>(GetProcAddress(module, "?width@Pixmap@@QBEIXZ"));
|
|
found.height = reinterpret_cast<Getter>(GetProcAddress(module, "?height@Pixmap@@QBEIXZ"));
|
|
found.rowBytes = reinterpret_cast<Getter>(GetProcAddress(module, "?rowBytes@Pixmap@@QBEIXZ"));
|
|
found.pixels = reinterpret_cast<PixelsGetter>(GetProcAddress(module, "?pixels@Pixmap@@QBEPAIXZ"));
|
|
found.construct = reinterpret_cast<SizeConstructor>(GetProcAddress(module, "??0Pixmap@@QAE@HH@Z"));
|
|
found.constructEmpty = reinterpret_cast<DefaultConstructor>(GetProcAddress(module, "??0Pixmap@@QAE@XZ"));
|
|
found.copy = reinterpret_cast<CopyConstructor>(GetProcAddress(module, "??0Pixmap@@QAE@ABV0@@Z"));
|
|
found.destroy = reinterpret_cast<Destructor>(GetProcAddress(module, "??1Pixmap@@QAE@XZ"));
|
|
}
|
|
return found;
|
|
}();
|
|
return methods;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::optional<PixmapPixels> 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<imvu::Pixmap*>(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
|