diff --git a/src/experimental/filament/filament/filament_context.cc b/src/experimental/filament/filament/filament_context.cc index 3b3a632e..672f1541 100644 --- a/src/experimental/filament/filament/filament_context.cc +++ b/src/experimental/filament/filament/filament_context.cc @@ -316,6 +316,15 @@ void FilamentContext::UploadHeightField(const mjModel* model, int id) { object_manager_->UploadHeightField(model, id); } +uintptr_t FilamentContext::UploadGuiImage(uintptr_t tex_id, + const uint8_t* pixels, int width, + int height, int bpp) { + if (gui_view_) { + return gui_view_->UploadImage(tex_id, pixels, width, height, bpp); + } + return 0; +} + double FilamentContext::GetFrameRate() const { utils::FixedCapacityVector frame_info = renderer_->getFrameInfoHistory(1); diff --git a/src/experimental/filament/filament/filament_context.h b/src/experimental/filament/filament/filament_context.h index 5d179583..9b5e67f0 100644 --- a/src/experimental/filament/filament/filament_context.h +++ b/src/experimental/filament/filament/filament_context.h @@ -51,6 +51,9 @@ class FilamentContext { void UploadHeightField(const mjModel* model, int id); + uintptr_t UploadGuiImage(uintptr_t tex_id, const uint8_t* pixels, int width, + int height, int bpp); + double GetFrameRate() const; FilamentContext(const FilamentContext&) = delete; diff --git a/src/experimental/filament/filament/gui_view.cc b/src/experimental/filament/filament/gui_view.cc index d7fcd7d9..1f7b7b8e 100644 --- a/src/experimental/filament/filament/gui_view.cc +++ b/src/experimental/filament/filament/gui_view.cc @@ -83,6 +83,49 @@ void GuiView::ResetRenderable() { buffers_.clear(); } +uintptr_t GuiView::UploadImage(uintptr_t tex_id, const uint8_t* pixels, + int width, int height, int bpp) { + if (bpp != 4) { + mju_error("Unsupported image bpp. Got %d, wanted 4", bpp); + } + + filament::Engine* engine = object_mgr_->GetEngine(); + + filament::Texture* texture = nullptr; + if (tex_id == 0) { + texture = filament::Texture::Builder() + .width(width) + .height(height) + .levels(1) + .format(filament::Texture::InternalFormat::RGBA8) + .sampler(filament::Texture::Sampler::SAMPLER_2D) + .build(*engine); + tex_id = reinterpret_cast(texture); + textures_[tex_id] = texture; + } else { + auto iter = textures_.find(tex_id); + if (iter == textures_.end()) { + mju_error("Texture not found: %lu", tex_id); + } + texture = iter->second; + } + + // Create a copy of the image to pass it to filament as we don't know the + // lifetime of the data. + const int num_bytes = width * height * bpp; + std::byte* bytes = new std::byte[num_bytes]; + std::memcpy(bytes, pixels, num_bytes); + const auto callback = [](void* buffer, size_t size, void* user) { + auto* ptr = reinterpret_cast(user); + delete[] ptr; + }; + filament::Texture::PixelBufferDescriptor pb( + bytes, num_bytes, filament::Texture::Format::RGBA, + filament::Texture::Type::UBYTE, callback); + texture->setImage(*engine, 0, std::move(pb)); + return tex_id; +} + void GuiView::CreateTexture(ImTextureData* data) { filament::Engine* engine = object_mgr_->GetEngine(); if (data->Format != ImTextureFormat_RGBA32) { @@ -256,18 +299,16 @@ filament::MaterialInstance* GuiView::GetMaterialInstance(int index, mjrRect rect, uintptr_t texture_id) { while (index >= instances_.size()) { - auto iter = textures_.find(texture_id); - if (iter == textures_.end()) { - mju_error("Texture not found: %lu", texture_id); - } + instances_.push_back(material_->createInstance()); + } - filament::TextureSampler sampler; - filament::MaterialInstance* instance = material_->createInstance(); - instance->setParameter("glyph", iter->second, sampler); - instances_.push_back(instance); + auto iter = textures_.find(texture_id); + if (iter == textures_.end()) { + mju_error("Texture not found: %lu", texture_id); } filament::MaterialInstance* instance = instances_[index]; + instance->setParameter("glyph", iter->second, filament::TextureSampler()); instance->setScissor(rect.left, rect.bottom, rect.width, rect.height); return instance; } diff --git a/src/experimental/filament/filament/gui_view.h b/src/experimental/filament/filament/gui_view.h index 6498c6e8..3c1a9418 100644 --- a/src/experimental/filament/filament/gui_view.h +++ b/src/experimental/filament/filament/gui_view.h @@ -47,6 +47,10 @@ class GuiView { // Returns the filament::View used to render the UX scene. filament::View* PrepareRenderView(); + // Uploads texture to be used with ImGui's Image and ImageButton functions. + uintptr_t UploadImage(uintptr_t tex_id, const uint8_t* pixels, int width, + int height, int bpp); + private: void CreateTexture(ImTextureData* data); void UpdateTexture(ImTextureData* data); diff --git a/src/experimental/filament/render_context_filament.cc b/src/experimental/filament/render_context_filament.cc index cada07de..a74536aa 100644 --- a/src/experimental/filament/render_context_filament.cc +++ b/src/experimental/filament/render_context_filament.cc @@ -137,6 +137,13 @@ void mjr_readPixels(unsigned char* rgb, float* depth, mjrRect viewport, g_filament_context->ReadPixels(viewport, rgb, depth); } +uintptr_t mjr_uploadGuiImage(uintptr_t tex_id, const unsigned char* pixels, + int width, int height, int bpp, + const mjrContext* con) { + CheckFilamentContext(); + return g_filament_context->UploadGuiImage(tex_id, pixels, width, height, bpp); +} + double mjr_getFrameRate(const mjrContext* con) { CheckFilamentContext(); return g_filament_context->GetFrameRate(); diff --git a/src/experimental/filament/render_context_filament.h b/src/experimental/filament/render_context_filament.h index 2625ab2f..3e88f8ab 100644 --- a/src/experimental/filament/render_context_filament.h +++ b/src/experimental/filament/render_context_filament.h @@ -81,6 +81,10 @@ MJAPI void mjr_readPixels(unsigned char* rgb, float* depth, mjrRect viewport, double mjr_getFrameRate(const mjrContext* con); +uintptr_t mjr_uploadGuiImage(uintptr_t tex_id, const unsigned char* pixels, + int width, int height, int bpp, + const mjrContext* con); + #if defined(__cplusplus) } // extern "C" #endif