mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2025-04-07 05:56:53 +02:00
Add basic thumbnail parsing functionality.
This commit is contained in:
parent
13a22b1504
commit
937f390331
@ -109,6 +109,8 @@ namespace recompui {
|
||||
Rml::ElementPtr create_custom_element(Rml::Element* parent, std::string tag);
|
||||
Rml::ElementDocument* load_document(const std::filesystem::path& path);
|
||||
Rml::ElementDocument* create_empty_document();
|
||||
void queue_image_from_bytes(const std::string &src, const std::vector<char> &bytes);
|
||||
void release_image(const std::string &src);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -252,6 +252,10 @@ void Element::set_text(std::string_view text) {
|
||||
base->SetInnerRML(std::string(text));
|
||||
}
|
||||
|
||||
void Element::set_src(std::string_view src) {
|
||||
base->SetAttribute("src", std::string(src));
|
||||
}
|
||||
|
||||
void Element::set_style_enabled(std::string_view style_name, bool enable) {
|
||||
if (enable && style_active_set.find(style_name) == style_active_set.end()) {
|
||||
// Style was disabled and will be enabled.
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
void set_enabled(bool enabled);
|
||||
bool is_enabled() const;
|
||||
void set_text(std::string_view text);
|
||||
void set_src(std::string_view src);
|
||||
void set_style_enabled(std::string_view style_name, bool enabled);
|
||||
bool is_element() override { return true; }
|
||||
float get_absolute_left();
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
namespace recompui {
|
||||
|
||||
Image::Image(Element *parent) : Element(parent) {
|
||||
|
||||
Image::Image(Element *parent, std::string_view src) : Element(parent, 0, "img") {
|
||||
set_src(src);
|
||||
}
|
||||
|
||||
};
|
@ -6,7 +6,7 @@ namespace recompui {
|
||||
|
||||
class Image : public Element {
|
||||
public:
|
||||
Image(Element *parent);
|
||||
Image(Element *parent, std::string_view src);
|
||||
};
|
||||
|
||||
} // namespace recompui
|
@ -23,7 +23,7 @@ ModDetailsPanel::ModDetailsPanel(Element *parent) : Element(parent) {
|
||||
thumbnail_container = context.create_element<Container>(header_container, FlexDirection::Column, JustifyContent::SpaceEvenly);
|
||||
thumbnail_container->set_flex(0.0f, 0.0f);
|
||||
{
|
||||
thumbnail_image = context.create_element<Image>(thumbnail_container);
|
||||
thumbnail_image = context.create_element<Image>(thumbnail_container, "");
|
||||
thumbnail_image->set_width(100.0f);
|
||||
thumbnail_image->set_height(100.0f);
|
||||
thumbnail_image->set_background_color(Color{ 190, 184, 219, 25 });
|
||||
@ -67,9 +67,11 @@ ModDetailsPanel::ModDetailsPanel(Element *parent) : Element(parent) {
|
||||
ModDetailsPanel::~ModDetailsPanel() {
|
||||
}
|
||||
|
||||
void ModDetailsPanel::set_mod_details(const recomp::mods::ModDetails& details, bool mod_enabled, bool toggle_enabled) {
|
||||
void ModDetailsPanel::set_mod_details(const recomp::mods::ModDetails& details, const std::string &thumbnail, bool mod_enabled, bool toggle_enabled) {
|
||||
cur_details = details;
|
||||
|
||||
thumbnail_image->set_src(thumbnail);
|
||||
|
||||
title_label->set_text(cur_details.display_name);
|
||||
version_label->set_text(cur_details.version.to_string());
|
||||
|
||||
|
@ -14,7 +14,7 @@ class ModDetailsPanel : public Element {
|
||||
public:
|
||||
ModDetailsPanel(Element *parent);
|
||||
virtual ~ModDetailsPanel();
|
||||
void set_mod_details(const recomp::mods::ModDetails& details, bool mod_enabled, bool toggle_enabled);
|
||||
void set_mod_details(const recomp::mods::ModDetails& details, const std::string &thumbnail, bool mod_enabled, bool toggle_enabled);
|
||||
void set_mod_toggled_callback(std::function<void(bool)> callback);
|
||||
void set_mod_configure_pressed_callback(std::function<void()> callback);
|
||||
private:
|
||||
|
@ -15,6 +15,10 @@
|
||||
|
||||
namespace recompui {
|
||||
|
||||
static std::string generate_thumbnail_src_for_mod(const std::string &mod_id) {
|
||||
return "?/mods/" + mod_id + "/thumb";
|
||||
}
|
||||
|
||||
// ModEntryView
|
||||
|
||||
ModEntryView::ModEntryView(Element *parent) : Element(parent) {
|
||||
@ -34,13 +38,14 @@ ModEntryView::ModEntryView(Element *parent) : Element(parent) {
|
||||
set_cursor(Cursor::Pointer);
|
||||
|
||||
{
|
||||
thumbnail_image = context.create_element<Image>(this);
|
||||
thumbnail_image = context.create_element<Image>(this, "");
|
||||
thumbnail_image->set_width(100.0f);
|
||||
thumbnail_image->set_height(100.0f);
|
||||
thumbnail_image->set_min_width(100.0f);
|
||||
thumbnail_image->set_min_height(100.0f);
|
||||
thumbnail_image->set_background_color(Color{ 190, 184, 219, 25 });
|
||||
|
||||
|
||||
body_container = context.create_element<Container>(this, FlexDirection::Column, JustifyContent::FlexStart);
|
||||
body_container->set_width_auto();
|
||||
body_container->set_height(100.0f);
|
||||
@ -63,6 +68,10 @@ void ModEntryView::set_mod_details(const recomp::mods::ModDetails &details) {
|
||||
description_label->set_text(details.short_description);
|
||||
}
|
||||
|
||||
void ModEntryView::set_mod_thumbnail(const std::string &thumbnail) {
|
||||
thumbnail_image->set_src(thumbnail);
|
||||
}
|
||||
|
||||
// ModEntryButton
|
||||
|
||||
ModEntryButton::ModEntryButton(Element *parent, uint32_t mod_index) : Element(parent, Events(EventType::Click, EventType::Hover, EventType::Focus, EventType::Drag)) {
|
||||
@ -90,6 +99,10 @@ void ModEntryButton::set_mod_details(const recomp::mods::ModDetails &details) {
|
||||
view->set_mod_details(details);
|
||||
}
|
||||
|
||||
void ModEntryButton::set_mod_thumbnail(const std::string &thumbnail) {
|
||||
view->set_mod_thumbnail(thumbnail);
|
||||
}
|
||||
|
||||
void ModEntryButton::process_event(const Event& e) {
|
||||
switch (e.type) {
|
||||
case EventType::Click:
|
||||
@ -110,6 +123,10 @@ void ModEntryButton::process_event(const Event& e) {
|
||||
// ModMenu
|
||||
|
||||
void ModMenu::refresh_mods() {
|
||||
for (const std::string &thumbnail : loaded_thumbnails) {
|
||||
recompui::release_image(thumbnail);
|
||||
}
|
||||
|
||||
recomp::mods::scan_mods();
|
||||
mod_details = recomp::mods::get_mod_details(game_mod_id);
|
||||
create_mod_list();
|
||||
@ -137,10 +154,11 @@ void ModMenu::mod_toggled(bool enabled) {
|
||||
void ModMenu::mod_selected(uint32_t mod_index) {
|
||||
active_mod_index = mod_index;
|
||||
if (active_mod_index >= 0) {
|
||||
std::string thumbnail_src = generate_thumbnail_src_for_mod(mod_details[mod_index].mod_id);
|
||||
bool mod_enabled = recomp::mods::is_mod_enabled(mod_details[mod_index].mod_id);
|
||||
bool auto_enabled = recomp::mods::is_mod_auto_enabled(mod_details[mod_index].mod_id);
|
||||
bool toggle_enabled = !auto_enabled && (mod_details[mod_index].runtime_toggleable || !ultramodern::is_game_started());
|
||||
mod_details_panel->set_mod_details(mod_details[mod_index], mod_enabled, toggle_enabled);
|
||||
mod_details_panel->set_mod_details(mod_details[mod_index], thumbnail_src, mod_enabled, toggle_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,6 +179,7 @@ void ModMenu::mod_dragged(uint32_t mod_index, EventDrag drag) {
|
||||
mod_entry_buttons[mod_index]->set_display(Display::None);
|
||||
mod_entry_floating_view->set_display(Display::Flex);
|
||||
mod_entry_floating_view->set_mod_details(mod_details[mod_index]);
|
||||
mod_entry_floating_view->set_mod_thumbnail(generate_thumbnail_src_for_mod(mod_details[mod_index].mod_id));
|
||||
mod_entry_floating_view->set_left(left, Unit::Px);
|
||||
mod_entry_floating_view->set_top(top, Unit::Px);
|
||||
mod_entry_floating_view->set_width(width, Unit::Px);
|
||||
@ -218,7 +237,9 @@ void ModMenu::mod_dragged(uint32_t mod_index, EventDrag drag) {
|
||||
mod_details = recomp::mods::get_mod_details(game_mod_id);
|
||||
for (size_t i = 0; i < mod_entry_buttons.size(); i++) {
|
||||
mod_entry_buttons[i]->set_mod_details(mod_details[i]);
|
||||
mod_entry_buttons[i]->set_mod_thumbnail(generate_thumbnail_src_for_mod(mod_details[i].mod_id));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -311,6 +332,13 @@ void ModMenu::create_mod_list() {
|
||||
|
||||
// Create the child elements for the list scroll.
|
||||
for (size_t mod_index = 0; mod_index < mod_details.size(); mod_index++) {
|
||||
const std::vector<char> &thumbnail = recomp::mods::get_mod_thumbnail(mod_details[mod_index].mod_id);
|
||||
std::string thumbnail_name = generate_thumbnail_src_for_mod(mod_details[mod_index].mod_id);
|
||||
if (!thumbnail.empty()) {
|
||||
recompui::queue_image_from_bytes(thumbnail_name, thumbnail);
|
||||
loaded_thumbnails.emplace(thumbnail_name);
|
||||
}
|
||||
|
||||
Element *spacer = context.create_element<Element>(list_scroll_container);
|
||||
mod_entry_spacers.emplace_back(spacer);
|
||||
|
||||
@ -318,6 +346,7 @@ void ModMenu::create_mod_list() {
|
||||
mod_entry->set_mod_selected_callback(std::bind(&ModMenu::mod_selected, this, std::placeholders::_1));
|
||||
mod_entry->set_mod_drag_callback(std::bind(&ModMenu::mod_dragged, this, std::placeholders::_1, std::placeholders::_2));
|
||||
mod_entry->set_mod_details(mod_details[mod_index]);
|
||||
mod_entry->set_mod_thumbnail(thumbnail_name);
|
||||
mod_entry_buttons.emplace_back(mod_entry);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ public:
|
||||
ModEntryView(Element *parent);
|
||||
virtual ~ModEntryView();
|
||||
void set_mod_details(const recomp::mods::ModDetails &details);
|
||||
void set_mod_thumbnail(const std::string &thumbnail);
|
||||
private:
|
||||
Image *thumbnail_image = nullptr;
|
||||
Container *body_container = nullptr;
|
||||
@ -29,6 +30,7 @@ public:
|
||||
void set_mod_selected_callback(std::function<void(uint32_t)> callback);
|
||||
void set_mod_drag_callback(std::function<void(uint32_t, EventDrag)> callback);
|
||||
void set_mod_details(const recomp::mods::ModDetails &details);
|
||||
void set_mod_thumbnail(const std::string &thumbnail);
|
||||
protected:
|
||||
virtual void process_event(const Event &e);
|
||||
private:
|
||||
@ -71,6 +73,7 @@ private:
|
||||
uint32_t mod_drag_target_index = 0;
|
||||
float mod_drag_spacer_height = 0.0f;
|
||||
std::vector<recomp::mods::ModDetails> mod_details{};
|
||||
std::unordered_set<std::string> loaded_thumbnails;
|
||||
std::string game_mod_id;
|
||||
|
||||
ConfigSubMenu *config_sub_menu;
|
||||
|
@ -6,6 +6,10 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
#include <concurrentqueue.h>
|
||||
|
||||
#include "stb/stb_image.h"
|
||||
|
||||
#include "rt64_render_hooks.h"
|
||||
#include "rt64_render_interface_builders.h"
|
||||
|
||||
@ -61,33 +65,16 @@ struct RmlPushConstants {
|
||||
struct TextureHandle {
|
||||
std::unique_ptr<RT64::RenderTexture> texture;
|
||||
std::unique_ptr<RT64::RenderDescriptorSet> set;
|
||||
bool transitioned = false;
|
||||
};
|
||||
|
||||
static std::vector<char> read_file(const std::filesystem::path& filepath) {
|
||||
std::vector<char> ret{};
|
||||
std::ifstream input_file{ filepath, std::ios::binary };
|
||||
|
||||
if (!input_file) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
input_file.seekg(0, std::ios::end);
|
||||
std::streampos filesize = input_file.tellg();
|
||||
input_file.seekg(0, std::ios::beg);
|
||||
|
||||
ret.resize(filesize);
|
||||
|
||||
input_file.read(ret.data(), filesize);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
T from_bytes_le(const char* input) {
|
||||
return *reinterpret_cast<const T*>(input);
|
||||
}
|
||||
|
||||
typedef std::pair<std::string, std::vector<char>> ImageFromBytes;
|
||||
|
||||
namespace recompui {
|
||||
class RmlRenderInterface_RT64_impl : public Rml::RenderInterfaceCompatibility {
|
||||
struct DynamicBuffer {
|
||||
@ -140,12 +127,19 @@ class RmlRenderInterface_RT64_impl : public Rml::RenderInterfaceCompatibility {
|
||||
std::unique_ptr<RT64::RenderFramebuffer> screen_framebuffer_{};
|
||||
std::unique_ptr<RT64::RenderDescriptorSet> screen_descriptor_set_{};
|
||||
std::unique_ptr<RT64::RenderBuffer> screen_vertex_buffer_{};
|
||||
std::unique_ptr<RT64::RenderCommandQueue> copy_command_queue_{};
|
||||
std::unique_ptr<RT64::RenderCommandList> copy_command_list_{};
|
||||
std::unique_ptr<RT64::RenderBuffer> copy_buffer_{};
|
||||
std::unique_ptr<RT64::RenderCommandFence> copy_command_fence_;
|
||||
uint64_t copy_buffer_size_ = 0;
|
||||
uint64_t screen_vertex_buffer_size_ = 0;
|
||||
uint32_t gTexture_descriptor_index;
|
||||
RT64::RenderInputSlot vertex_slot_{ 0, sizeof(Rml::Vertex) };
|
||||
RT64::RenderCommandList* list_ = nullptr;
|
||||
bool scissor_enabled_ = false;
|
||||
std::vector<std::unique_ptr<RT64::RenderBuffer>> stale_buffers_{};
|
||||
moodycamel::ConcurrentQueue<ImageFromBytes> image_from_bytes_queue;
|
||||
std::unordered_map<std::string, std::vector<char>> image_from_bytes_map;
|
||||
public:
|
||||
RmlRenderInterface_RT64_impl(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
|
||||
interface_ = interface;
|
||||
@ -251,6 +245,10 @@ public:
|
||||
vertices[2] = Rml::Vertex{ Rml::Vector2f(3.0f, 1.0f), white, Rml::Vector2f(2.0f, 0.0f) };
|
||||
screen_vertex_buffer_->unmap();
|
||||
}
|
||||
|
||||
copy_command_queue_ = device->createCommandQueue(RT64::RenderCommandListType::COPY);
|
||||
copy_command_list_ = device->createCommandList(RT64::RenderCommandListType::COPY);
|
||||
copy_command_fence_ = device->createCommandFence();
|
||||
}
|
||||
|
||||
void reset_dynamic_buffer(DynamicBuffer &dynamic_buffer) {
|
||||
@ -360,7 +358,15 @@ public:
|
||||
list_->setIndexBuffer(&index_view);
|
||||
RT64::RenderVertexBufferView vertex_view{vertex_buffer_.buffer_->at(vertex_buffer_offset), vert_size_bytes};
|
||||
list_->setVertexBuffers(0, &vertex_view, 1, &vertex_slot_);
|
||||
list_->setGraphicsDescriptorSet(textures_.at(texture).set.get(), 1);
|
||||
|
||||
TextureHandle &texture_handle = textures_.at(texture);
|
||||
if (!texture_handle.transitioned) {
|
||||
// Prepare the texture for being read from a pixel shader.
|
||||
list_->barriers(RT64::RenderBarrierStage::GRAPHICS, RT64::RenderTextureBarrier(texture_handle.texture.get(), RT64::RenderTextureLayout::SHADER_READ));
|
||||
texture_handle.transitioned = true;
|
||||
}
|
||||
|
||||
list_->setGraphicsDescriptorSet(texture_handle.set.get(), 1);
|
||||
|
||||
RmlPushConstants constants{
|
||||
.transform = mvp_,
|
||||
@ -384,72 +390,32 @@ public:
|
||||
}
|
||||
|
||||
bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override {
|
||||
std::filesystem::path image_path{ source.c_str() };
|
||||
flush_image_from_bytes_queue();
|
||||
|
||||
if (image_path.extension() == ".tga") {
|
||||
std::vector<char> file_data = read_file(image_path);
|
||||
|
||||
if (file_data.empty()) {
|
||||
printf(" File not found or empty\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure ID length is zero
|
||||
if (file_data[0] != 0) {
|
||||
printf(" Nonzero ID length not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure no color map is used
|
||||
if (file_data[1] != 0) {
|
||||
printf(" Color maps not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the image is uncompressed
|
||||
if (file_data[2] != 2) {
|
||||
printf(" Only uncompressed tga files supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t origin_x = from_bytes_le<uint16_t>(file_data.data() + 8);
|
||||
uint16_t origin_y = from_bytes_le<uint16_t>(file_data.data() + 10);
|
||||
uint16_t size_x = from_bytes_le<uint16_t>(file_data.data() + 12);
|
||||
uint16_t size_y = from_bytes_le<uint16_t>(file_data.data() + 14);
|
||||
|
||||
// Nonzero origin not supported
|
||||
if (origin_x != 0 || origin_y != 0) {
|
||||
printf(" Nonzero origin not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t pixel_depth = file_data[16];
|
||||
|
||||
if (pixel_depth != 32) {
|
||||
printf(" Only 32bpp images supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t image_descriptor = file_data[17];
|
||||
|
||||
if ((image_descriptor & 0b1111) != 8) {
|
||||
printf(" Only 8bpp alpha supported\n");
|
||||
}
|
||||
|
||||
if (image_descriptor & 0b110000) {
|
||||
printf(" Only bottom-to-top, left-to-right pixel order supported\n");
|
||||
}
|
||||
|
||||
texture_dimensions.x = size_x;
|
||||
texture_dimensions.y = size_y;
|
||||
|
||||
texture_handle = texture_count_++;
|
||||
create_texture(texture_handle, reinterpret_cast<const Rml::byte*>(file_data.data() + 18), texture_dimensions, true, true);
|
||||
|
||||
return true;
|
||||
auto it = image_from_bytes_map.find(source);
|
||||
if (it == image_from_bytes_map.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr uint32_t PNG_MAGIC = 0x474E5089;
|
||||
uint32_t magicNumber = *reinterpret_cast<const uint32_t *>(it->second.data());
|
||||
if (magicNumber == PNG_MAGIC) {
|
||||
int width, height;
|
||||
stbi_uc *stbi_data = stbi_load_from_memory((const stbi_uc *)(it->second.data()), it->second.size(), &width, &height, nullptr, 4);
|
||||
if (stbi_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
texture_dimensions.x = width;
|
||||
texture_dimensions.y = height;
|
||||
|
||||
bool texture_generated = GenerateTexture(texture_handle, stbi_data, texture_dimensions);
|
||||
stbi_image_free(stbi_data);
|
||||
return texture_generated;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override {
|
||||
@ -479,11 +445,13 @@ public:
|
||||
uint32_t uploaded_size_bytes = row_byte_width * source_dimensions.y;
|
||||
|
||||
// Allocate room in the upload buffer for the uploaded data.
|
||||
uint32_t upload_buffer_offset = allocate_dynamic_data_aligned(upload_buffer_, uploaded_size_bytes, 512);
|
||||
if (uploaded_size_bytes > copy_buffer_size_) {
|
||||
copy_buffer_size_ = (uploaded_size_bytes * 3) / 2;
|
||||
copy_buffer_ = device_->createBuffer(RT64::RenderBufferDesc::UploadBuffer(copy_buffer_size_));
|
||||
}
|
||||
|
||||
// Copy the source data into the upload buffer.
|
||||
uint8_t* dst_data = upload_buffer_.mapped_data_ + upload_buffer_offset;
|
||||
|
||||
uint8_t* dst_data = (uint8_t *)(copy_buffer_->map());
|
||||
if (row_byte_padding == 0) {
|
||||
// Copy row-by-row if the image is flipped.
|
||||
if (flip_y) {
|
||||
@ -508,23 +476,30 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
copy_buffer_->unmap();
|
||||
|
||||
// Reset the command list.
|
||||
copy_command_list_->begin();
|
||||
|
||||
// Prepare the texture to be a destination for copying.
|
||||
list_->barriers(RT64::RenderBarrierStage::COPY, RT64::RenderTextureBarrier(texture.get(), RT64::RenderTextureLayout::COPY_DEST));
|
||||
copy_command_list_->barriers(RT64::RenderBarrierStage::COPY, RT64::RenderTextureBarrier(texture.get(), RT64::RenderTextureLayout::COPY_DEST));
|
||||
|
||||
// Copy the upload buffer into the texture.
|
||||
list_->copyTextureRegion(
|
||||
copy_command_list_->copyTextureRegion(
|
||||
RT64::RenderTextureCopyLocation::Subresource(texture.get()),
|
||||
RT64::RenderTextureCopyLocation::PlacedFootprint(upload_buffer_.buffer_.get(), RmlTextureFormat, source_dimensions.x, source_dimensions.y, 1, row_width, upload_buffer_offset));
|
||||
RT64::RenderTextureCopyLocation::PlacedFootprint(copy_buffer_.get(), RmlTextureFormat, source_dimensions.x, source_dimensions.y, 1, row_width));
|
||||
|
||||
// Prepare the texture for being read from a pixel shader.
|
||||
list_->barriers(RT64::RenderBarrierStage::GRAPHICS, RT64::RenderTextureBarrier(texture.get(), RT64::RenderTextureLayout::SHADER_READ));
|
||||
// End the command list, execute it and wait.
|
||||
copy_command_list_->end();
|
||||
copy_command_queue_->executeCommandLists(copy_command_list_.get(), copy_command_fence_.get());
|
||||
copy_command_queue_->waitForCommandFence(copy_command_fence_.get());
|
||||
|
||||
// Create a descriptor set with this texture in it.
|
||||
std::unique_ptr<RT64::RenderDescriptorSet> set = texture_set_builder_->create(device_);
|
||||
|
||||
set->setTexture(gTexture_descriptor_index, texture.get(), RT64::RenderTextureLayout::SHADER_READ);
|
||||
|
||||
textures_.emplace(texture_handle, TextureHandle{ std::move(texture), std::move(set) });
|
||||
textures_.emplace(texture_handle, TextureHandle{ std::move(texture), std::move(set), false });
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -625,6 +600,17 @@ public:
|
||||
|
||||
list_ = nullptr;
|
||||
}
|
||||
|
||||
void queue_image_from_bytes(const std::string &src, const std::vector<char> &bytes) {
|
||||
image_from_bytes_queue.enqueue(ImageFromBytes(src, bytes));
|
||||
}
|
||||
|
||||
void flush_image_from_bytes_queue() {
|
||||
ImageFromBytes image_from_bytes;
|
||||
while (image_from_bytes_queue.try_dequeue(image_from_bytes)) {
|
||||
image_from_bytes_map.emplace(image_from_bytes.first, std::move(image_from_bytes.second));
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace recompui
|
||||
|
||||
@ -657,3 +643,9 @@ void recompui::RmlRenderInterface_RT64::end(RT64::RenderCommandList* list, RT64:
|
||||
|
||||
impl->end(list, framebuffer);
|
||||
}
|
||||
|
||||
void recompui::RmlRenderInterface_RT64::queue_image_from_bytes(const std::string &src, const std::vector<char> &bytes) {
|
||||
assert(static_cast<bool>(impl));
|
||||
|
||||
impl->queue_image_from_bytes(src, bytes);
|
||||
}
|
@ -29,6 +29,7 @@ namespace recompui {
|
||||
|
||||
void start(RT64::RenderCommandList* list, int image_width, int image_height);
|
||||
void end(RT64::RenderCommandList* list, RT64::RenderFramebuffer* framebuffer);
|
||||
void queue_image_from_bytes(const std::string &src, const std::vector<char> &bytes);
|
||||
};
|
||||
} // namespace recompui
|
||||
|
||||
|
@ -775,3 +775,10 @@ Rml::ElementDocument* recompui::create_empty_document() {
|
||||
return ui_state->context->CreateDocument();
|
||||
}
|
||||
|
||||
void recompui::queue_image_from_bytes(const std::string &src, const std::vector<char> &bytes) {
|
||||
ui_state->render_interface.queue_image_from_bytes(src, bytes);
|
||||
}
|
||||
|
||||
void recompui::release_image(const std::string &src) {
|
||||
Rml::ReleaseTexture(src);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user