#include "resources.hpp" #include #include #include #include #include #include "log.hpp" namespace t5de { namespace { // Our live resources, by address. struct Registry { std::mutex mutex; std::unordered_set objects; }; Registry& registry() { static Registry instance; return instance; } void add(const void* object) { const std::scoped_lock lock(registry().mutex); registry().objects.insert(object); } void remove(const void* object) { const std::scoped_lock lock(registry().mutex); registry().objects.erase(object); } } // namespace bool ours(const void* object) { if (object == nullptr) { return false; } const std::scoped_lock lock(registry().mutex); return registry().objects.contains(object); } Texture::Texture(imvu::PiRenderTexture* inner, std::shared_ptr recorder, std::uint32_t id) : inner_(inner), recorder_(std::move(recorder)), id_(id) { add(static_cast(this)); } Texture::Texture(std::shared_ptr recorder, std::uint32_t targetId, imvu::Vec2i size) : inner_(nullptr), recorder_(std::move(recorder)), id_(targetId), size_(size), ownsId_(false) { add(static_cast(this)); } Texture::~Texture() { remove(static_cast(this)); delete inner_; // through its virtual destructor: IMVU's code frees it if (ownsId_) { recorder_->destroyTexture(id_); } } imvu::Vec2i Texture::size() const { return inner_ != nullptr ? inner_->size() : size_; } void Texture::updateRegions(const imvu::Pixmap& pixmap, const imvu::CompoundRegion& regions) { if (inner_ != nullptr) { inner_->updateRegions(pixmap, regions); recorder_->updateTexture(id_, pixmap); // all of it: the regions' layout isn't known } } void Texture::update(const imvu::Pixmap& pixmap) { if (inner_ != nullptr) { inner_->update(pixmap); recorder_->updateTexture(id_, pixmap); } } imvu::Pixmap* Texture::read(imvu::Pixmap* result) const { if (inner_ != nullptr) { return inner_->read(result); } // A render target's texture: not read back (not seen used); an image of its size. log::info("texture: a render target's texture read; not supported, returning a blank image"); return OwnedPixmap(size_.x, size_.y).copyTo(result); } IndexBuffer::IndexBuffer(imvu::PiInternalIndexBuffer* inner, std::shared_ptr recorder, std::uint32_t id) : inner_(inner), recorder_(std::move(recorder)), id_(id) { add(static_cast(this)); } IndexBuffer::~IndexBuffer() { remove(static_cast(this)); delete inner_; recorder_->destroyBuffer(id_); } VertexBuffer::VertexBuffer(imvu::PiInternalVertexBuffer* inner, std::shared_ptr recorder, std::uint32_t id) : inner_(inner), recorder_(std::move(recorder)), id_(id) { add(static_cast(this)); } VertexBuffer::~VertexBuffer() { remove(static_cast(this)); delete inner_; recorder_->destroyBuffer(id_); } void VertexBuffer::update(const void* data, std::uint32_t stride, std::uint32_t elementSize, std::uint32_t elementCount) { inner_->update(data, stride, elementSize, elementCount); recorder_->updateBuffer(id_, data, stride, elementSize, elementCount); } void VertexBuffer::unknown2() { inner_->unknown2(); } PixmapTarget::PixmapTarget(std::shared_ptr recorder, imvu::Vec2i size) : recorder_(std::move(recorder)), id_(recorder_->createRenderTarget(static_cast(size.x), static_cast(size.y))), size_(size), pixmap_(size.x, size.y) { add(static_cast(this)); } PixmapTarget::~PixmapTarget() { remove(static_cast(this)); recorder_->destroyTexture(id_); } imvu::Pixmap* PixmapTarget::getPixmap(imvu::Pixmap* result) const { return pixmap_.copyTo(result); } void PixmapTarget::setPixels(std::span pixels) { const auto into = pixmap_.valid() ? pixmap_pixels(pixmap_.get()) : std::nullopt; const auto width = static_cast(size_.x); const auto height = static_cast(size_.y); const std::size_t rowSize = std::size_t{width} * 4; if (!into || into->pixels == nullptr || pixels.size() < rowSize * height) { log::info("render target: {}x{} frame not read back ({} bytes)", width, height, pixels.size()); return; } const std::size_t copied = std::min(rowSize, std::size_t{into->width} * 4); auto* rows = reinterpret_cast(into->pixels); for (std::uint32_t y = 0; y < std::min(into->height, height); ++y) { std::memcpy(rows + std::size_t{y} * into->rowBytes, pixels.data() + y * rowSize, copied); } } TextureTarget::TextureTarget(std::shared_ptr recorder, imvu::Vec2i size) : recorder_(std::move(recorder)), id_(recorder_->createRenderTarget(static_cast(size.x), static_cast(size.y))), size_(size) { add(static_cast(this)); } TextureTarget::~TextureTarget() { remove(static_cast(this)); recorder_->destroyTexture(id_); } imvu::TextureArea* TextureTarget::area(imvu::TextureArea* result) const { return new (result) imvu::TextureArea{0, 0, 1, 1}; } imvu::SharedPtr* TextureTarget::texture(imvu::SharedPtr* result) const { return new (result) imvu::SharedPtr( std::unique_ptr(new Texture(recorder_, id_, size_))); } } // namespace t5de