diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index f386442e..2dfdc647 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -80,22 +80,6 @@ PNGImage PNGImage::Load(const mjCBase* obj, mjResource* resource, LodePNGColorType color_type) { PNGImage image; image.color_type_ = color_type; - mjCCache *cache = reinterpret_cast(mj_getCache()->impl_); - - // cache callback - auto callback = [&image](const void* data) { - const PNGImage *cached_image = static_cast(data); - if (cached_image->color_type_ == image.color_type_) { - image = *cached_image; - return true; - } - return false; - }; - - // try loading from cache - if (cache && cache->PopulateData(resource->name, resource, callback)) { - return image; - } // open PNG resource const unsigned char* buffer; @@ -146,16 +130,6 @@ PNGImage PNGImage::Load(const mjCBase* obj, mjResource* resource, throw mjCError(obj, "%s", ss.str().c_str()); } - // insert raw image data into cache - if (cache) { - PNGImage *cached_image = new PNGImage(image);; - std::size_t size = image.Size(); - std::shared_ptr cached_data(cached_image, +[] (const void* data) { - delete static_cast(data); - }); - cache->Insert("", resource->name, resource, cached_data, size); - } - return image; } @@ -4397,6 +4371,12 @@ mjCHField::~mjCHField() { } +std::string mjCHField::GetCacheId(const mjResource* resource, const std::string& asset_type) { + std::stringstream ss; + ss << "mjCHField:" << resource->name << ";ARGS:content_type=" << asset_type; + return ss.str(); +} + // load elevation data from custom format void mjCHField::LoadCustom(mjResource* resource) { @@ -4493,6 +4473,8 @@ void mjCHField::Compile(const mjVFS* vfs) { throw mjCError(this, "hfield specified from file and manually"); } + mjCCache* cache = reinterpret_cast(mj_getCache()->impl_); + std::string asset_type = GetAssetContentType(file_, content_type_); // fallback to custom @@ -4514,16 +4496,46 @@ void mjCHField::Compile(const mjVFS* vfs) { FilePath filename = meshdir_ + FilePath(file_); mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs); - try { - if (asset_type == "image/png") { - LoadPNG(resource); - } else { - LoadCustom(resource); + struct CachedHField { + int nrow, ncol; + std::vector data; + }; + + // cache callback + auto callback = [&](const void* cached_data) { + const CachedHField* cached_hfield = + static_cast(cached_data); + nrow = cached_hfield->nrow; + ncol = cached_hfield->ncol; + this->data = cached_hfield->data; + return true; + }; + + // try loading from cache + if (cache && cache->PopulateData(GetCacheId(resource, asset_type), resource, callback)) { + mju_closeResource(resource); + } else { + try { + if (asset_type == "image/png") { + LoadPNG(resource); + } else { + LoadCustom(resource); + } + } catch(mjCError err) { + mju_closeResource(resource); + throw err; + } + + if (cache) { + CachedHField* cached_hfield = new CachedHField; + cached_hfield->nrow = nrow; + cached_hfield->ncol = ncol; + cached_hfield->data = this->data; + std::size_t size = sizeof(CachedHField) + this->data.size() * sizeof(float); + std::shared_ptr cached_data{cached_hfield}; + cache->Insert("", GetCacheId(resource, asset_type), resource, cached_data, size); } mju_closeResource(resource); - } catch(mjCError err) { - mju_closeResource(resource); - throw err; } } @@ -5021,10 +5033,36 @@ void mjCTexture::FlipIfNeeded(std::vector& image, unsigned int w, } } +std::string mjCTexture::GetCacheId(const mjResource* resource, const std::string& asset_type) { + std::stringstream ss; + ss << resource->name << ";ARGS:content_type=" << asset_type << ",nchannel=" << nchannel + << ",hflip=" << hflip << ",vflip=" << vflip << ";"; + return ss.str(); +} + // load from PNG or custom file, flip if specified void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs, std::vector& image, unsigned int& w, unsigned int& h, bool& is_srgb) { + mjCCache* cache = reinterpret_cast(mj_getCache()->impl_); + + struct CachedImage { + unsigned int w, h, n_ch; + bool is_srgb; + std::vector image; + }; + + // cache callback + auto callback = [&](const void* data) { + const CachedImage* cached_image = + static_cast(data); + w = cached_image->w; + h = cached_image->h; + is_srgb = cached_image->is_srgb; + image = cached_image->image; + return true; + }; + std::string asset_type = GetAssetContentType(filename, content_type_); // fallback to custom @@ -5036,7 +5074,12 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs, throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str()); } + // try loading from cache mjResource* resource = LoadResource(modelfiledir_.Str(), filename, vfs); + if (cache && cache->PopulateData(GetCacheId(resource, asset_type), resource, callback)) { + mju_closeResource(resource); + return; + } try { if (asset_type == "image/png") { @@ -5049,13 +5092,23 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs, } else { LoadCustom(resource, image, w, h, is_srgb); } - mju_closeResource(resource); } catch(mjCError err) { mju_closeResource(resource); throw err; } FlipIfNeeded(image, w, h); + if (cache) { + CachedImage* cached_texture = new CachedImage; + cached_texture->w = w; + cached_texture->h = h; + cached_texture->is_srgb = is_srgb; + cached_texture->image = image; + std::size_t size = sizeof(CachedImage) + image.size(); + std::shared_ptr cached_data{cached_texture}; + cache->Insert("", GetCacheId(resource, asset_type), resource, cached_data, size); + } + mju_closeResource(resource); } // load 2D diff --git a/src/user/user_objects.h b/src/user/user_objects.h index b541ce26..a92be73e 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -1395,6 +1395,7 @@ class mjCHField : public mjCHField_, private mjsHField { private: void Compile(const mjVFS* vfs); // compiler + std::string GetCacheId(const mjResource* resource, const std::string& asset_type); void LoadCustom(mjResource* resource); // load from custom format void LoadPNG(mjResource* resource); // load from PNG format }; @@ -1444,11 +1445,14 @@ class mjCTexture : public mjCTexture_, private mjsTexture { private: void Compile(const mjVFS* vfs); // compiler - void Builtin2D(void); // make builtin 2D - void BuiltinCube(void); // make builtin cube - void Load2D(std::string filename, const mjVFS* vfs); // load 2D from file - void LoadCubeSingle(std::string filename, const mjVFS* vfs); // load cube from single file - void LoadCubeSeparate(const mjVFS* vfs); // load cube from separate files + // store texture into asset cache + std::string GetCacheId(const mjResource* resource, const std::string& asset_type); + void Builtin2D(void); // make builtin 2D + void BuiltinCube(void); // make builtin cube + void Load2D(std::string filename, const mjVFS* vfs); // load 2D from file + void LoadCubeSingle(std::string filename, + const mjVFS* vfs); // load cube from single file + void LoadCubeSeparate(const mjVFS* vfs); // load cube from separate files void FlipIfNeeded(std::vector& image, unsigned int w, unsigned int h);